In this lesson, you will learn how to isolate your system-under-test (SUT) from the complexity of object instantiation by mocking factory abstractions.
The Factory Bottleneck
When your code uses the new keyword to create objects inside a method (e.g., var processor = new DataProcessor();), you create a tight coupling that is difficult to test. If DataProcessor talks to a database or a file system, your unit test becomes an integration test by default. To maintain unit test purity, we extract the creation logic into an interface: IDataProcessorFactory.
Mocking the Factory
Instead of letting the SUT instantiate objects directly, you inject the factory into the SUT's constructor. During testing, you don't need to provide a real factory; you provide a mock. By mocking the factory, you control exactly which transient object is returned to your SUT, allowing you to return a "canned" mock object that behaves exactly as you need for a specific test case.
Implementation Pattern
Consider this OrderService which needs to create an IInvoice transiently:
public class OrderService {
private readonly IInvoiceFactory _factory;
public OrderService(IInvoiceFactory factory) => _factory = factory;
public void ProcessOrder(Order order) {
var invoice = _factory.Create(order); // Transient object
invoice.Generate();
}
}
In your test, you don't care how the factory creates the invoice. You only care that the factory provides a specific mock invoice:
var mockInvoice = new Mock<IInvoice>();
var mockFactory = new Mock<IInvoiceFactory>();
// Setup the factory to return our controlled mock
mockFactory.Setup(f => f.Create(It.IsAny<Order>())).Returns(mockInvoice.Object);
var service = new OrderService(mockFactory.Object);
service.ProcessOrder(new Order());
// Verify the behavior of the transient object
mockInvoice.Verify(i => i.Generate(), Times.Once);
By mocking the factory abstraction, you transform a hidden dependency into an explicit one, ensuring your tests remain fast, deterministic, and isolated from the side effects of complex object creation.
Key Takeaway: Mocking factory abstractions allows you to inject controlled, transient dependencies into your SUT, effectively decoupling object creation from business logic.