Course contentsShow
← C#
Lesson 1638 of 1,90815. Software Quality and TestingFree lesson

Testing Factory Patterns

Mock factory abstractions to control the creation of transient objects during tests.

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.