Search code examples
javajunitmockitofactory-pattern

Mocking factory pattern in Java


It may look similar to my question. I have a simple animal factory.

public class AnimalFactory {

    public Animal getAnimal(String type) {
        if ("canine".equals(type)) {
            return new Dog();
        } else {
            return new Cat();
        }
    }

}

and class for

public interface Animal {
    void makeSound();
}

public class Dog extends Animal {
    void makeSound() {
    }
}

public class Dog extends Animal {
    void makeSound() {
    }
}

I have some doubts. Does AnimalFactory violate the dependency inversion principle? Is it possible to unit test AnimalFactory without making calls to the actual Dog and Cat classes or do I have to refactor my code?


Solution

  • You're not violating the dependency inversion principle if there are no dependencies to inject.

    In any case the Factory is a creational design pattern and you should test that it does indeed create (instantiate) the right things.

    Yes, you should test that it does return objects where instanceof Dog and instanceof Cat are true.

    If you must test your factory without actually calling the constructors of Dog and Cat (due to the initialization that they do), I suggest refactoring the factory class like this:

    public class AnimalFactory {
        public Animal createAnimal(String type) {
            if ("canine".equals(type)) {
                return createDog();
            } else {
                return createCat();
            }
        }
    
        Dog createDog() { return new Dog(); }
    
        Cat createCat() { return new Cat(); }
    }
    

    And the test would look like this:

    public class AnimalFactoryTest {
        @Test
        public void testCreateDog() throws Exception {
            AnimalFactory mockFactory = mock(AnimalFactory.class);
            when(mockFactory.createAnimal(anyString())).thenCallRealMethod();
    
            mockFactory.createAnimal("canine");
            verify(mockFactory).createDog();
        }
    
        @Test
        public void testCreateCat() throws Exception {
            AnimalFactory mockFactory = mock(AnimalFactory.class);
            when(mockFactory.createAnimal(anyString())).thenCallRealMethod();
    
            mockFactory.createAnimal("cat");
            verify(mockFactory).createCat();
        }
    }
    

    Incidentally, the naming convention for Factory pattern methods are createXyz rather than getXyz.

    Good luck.