Search code examples
unit-testingabstract-factory

Unit Test Parametric Abstract Factory


Consider the following design:

public class PhoneAbstractFactory
{
        public IPhoneFactory GetPhoneFactory(string type, bool needSmartPhone)
        {
            if (type == "Samsung")
                return new SamsungFactory(needSmartPhone);

            if (type == "Apple")
                return new AppleFactory(needSmartPhone);

            else throw new Exception("Unknown phone type: " + type);
        }
}

    public interface IPhoneFactory  { }

    public class SamsungFactory : IPhoneFactory
    {
        public SamsungFactory(bool needSmartPhone)
        {
        }
    }

    public class AppleFactory : IPhoneFactory
    {
        public AppleFactory(bool needSmartPhone)
        {
        }
    }

How can I test only PhoneAbstactFactory ? If I want to test it, inevitably an instance of either AppleFactory or SamsungFactory should get be instantiated; which means that if the test is to be passed, it is needed that constructing both of the factories must be always assumed truth-worthy. Otherwise, test scope spans over the two factories which is not good.


Solution

  • I think you are being too dogmatic about you definition of unit test.

    In the end the job of a factory class is to produce an instance of a class. In order to test that it must create that other class.

    A unit test does not necessarily test a single class but a unit of functionality or behavior (not the authour of the book linked doesn't say it tests one class, but one logical concept which:

    can span a single method, a whole class or multiple classes working together to achieve one single logical purpose that can be verified`

    ). This may involve several classes. Doing otherwise will end up with very brittle tests which must be changed every time the code is refactored, out tests which attempt to mock or stub every interaction with another class and this ends up jumping through ridiculous hoops (as you are trying to do here)

    Be pragmatic. Test the behavior you want you class to exhibit and do this in a way that if the implementation changes your tests won't have to, as far as possible. You'll make your life a lot easier both now and in the future.