In the real world, Factories manufacture items for output. In software engineering, Factories create object instances for us so we can avoid using the “new” operator. Factories also give us substantially more control when testing, and can even provide a means of verifying “Black box” operations.
Why would we want to avoid the “new” operator? Isn’t that what it’s there for?
Well, yes, but newing up a dependency within a class goes against the concept of dependency injection. Thinking back to our ReallyHardToTest class, we know we’re creating a new instance of SomeModel in the constructor, and one of our methods provides a way to change the SomeModel instance. The problem is that since we create the instance within ReallyHardToTest, we cannot control it or even verify that an instance is created. Furthermore, we can’t verify that the SetFilename method actually does what it says on the tin because the SomeModel instance isn’t exposed publicly by that class.
Factories Help Us Build Things
At its root, the factory pattern (there are actually a few variants) encapsulates the logic for creating instances of particular types. When employing these patterns, now dependent classes can have a factory injected, and then ask the factory for a new instance when they need it. Since the factory is injected, we can control it at test time – we even get to control the instance returned by the factory!
In advanced scenarios, for example when a factory will be invoked repeatedly, we can use advanced features of Moq, including SetupSequence() to return different instances in a specific order.
So Let’s Build a Factory!
Looking back at our ReallyHardToTest class, we can see that we want to create a factory for SomeModel, so let’s dive in!
So let’s start at line 22: We created a new ISomeModelFactory interface, followed by an implementing class for the factory. The factory itself is pretty self-explanatory, it just moves the new call into its own isolated class.
Note: It’s not always necessary to create a concrete factory class. Castle Windsor, for example, only requires you to specify the factory interface and register it as a factory. At runtime, it uses its TypedFactoryFacility (if configured) to create a concrete class that can inject all required dependencies.
Now we can scoot up to the constructor on line 11, which now has a new dependency on the factory interface, and now calls ISomeModelFactory.Create() to get a new SomeModel instance.
Fixing Up The Tests
So now let’s head over to our test fixture and update it to match:
Same old pattern here: We create a mock for our dependency and configure it in the SetUp method (since it’s invoked in the constructor). We also declare a field of type SomeModel on line 12 that we’ll be using shortly. Because we’re going to return this from our factory call, we instantiate it in StartUp and configure our mock factory to return it.
Whoa. I thought you said using ‘new’ is a bad thing?
Well, it is when it’s in production code, but in testing it’s OK. We have to have an instance for the factory to return. In the test environment we’re responsible for providing it to the mock’s configuration.
So let’s take a look at our Constructor_Always_PerformsExpectedWork test. Notice how we now have two VerifyAll calls, one to each mock that gets invoked in the constructor.
Sweet! That’s probably all we can test at this point, right?
Alas, no, we’re still missing one little detail. The SetFilename method on our class has a side effect, setting a property on the SomeModel class. Let’s go in for one final update…
So let’s look at line 37, where we verify that the model’s filename was set correctly. This is an example of how we can test internal functionality, given the correct architecture and patterns.
Conclusion and Next Steps:
Today we learned some things about factories, specifically that factories encapsulate creation logic. This encapsulation enables us to isolate creation logic and control object instantiation at test time. We also learned that with some creativity we can use the factory pattern to verify internal logic that is not accessible via public API.
In the end, we’ve got a fairly clean implementation with good test coverage, but there’s still some improvements we could make to the test class. Next time we’ll go over some additional Moq features that will help us make this test class even cleaner.