Factories

Factories generate entities on demand based on templated or predetermined initialization criteria. We most commonly think of the Gang of Four Abstract Factory [DP] pattern in this role. Other factories exist, including Factory Method and Builder [DP].

Each approach and implementation has distinct characteristics to satisfy its target use case. The key features for consideration in testing are summarized here.

Singleton-ness: Is the factory a singleton that will, by its nature, be shared between tests?

Entity initialization flexibility: Does the implementation have sufficient mechanisms to initialize generated entities for the necessary testing variations?

Registration management: Does the factory allow generated entity types to be registered and deregistered dynamically?

The variations in these characteristics determine the degree to which a particular factory implementation is desirable for use as a seam when testing.

Many implementations of the Abstract Factory pattern are also instances of the Singleton pattern. The reasoning is that a standardized source of entity generation should be the only source of those entities. For many applications, this satisfies the usage needs but has the same testing challenges of all singletons; primarily, tests will share the instance and run the risk of interfering with each other.

Factory methods can suffer from this limitation as well. By nature of their definition, they are singletons; there will generally be only one instance of a particular method because they are typically static, and the data sources that drive their behavior need to be singular.11

11. Note that some languages provide features that can mitigate these concerns. Using local in Perl to override subroutine definitions or substituting alternate function implementations on a particular object in JavaScript yields greater flexibility against these concerns.

Factories tend to have limited accommodations to initialize the entities that they create. The generalized nature of their role contributes to this; a mechanism that can generate a variety of entities needs to place sometimes-unacceptable constraints and requirements on those entities to initialize them consistently. Additionally, the need to create entities according to constraining requirements for their purposes motivates limiting the degree of customization that is allowed through the factory. While limited initialization of created entities may fit well within the design goals of the application, it can limit our ability to test the behavior of the factory.

Many applications statically configure their factories with the templates and instances necessary for their runtime behavior. Statically configured factories tightly couple your code to the types and implementations of the created entities, leading to undesirable coupling of the tests. Factories that support dynamic registration of created entities are much easier to test. They start in the test code uninitialized, allowing you to configure them with entities defined only within the tests, reducing the overall coupling of the test library.

As you can guess from reading the overview of the salient factory seams, only a narrow set of factory characteristics strongly support testability. To best support testability, a factory implementation should not be a singleton and should support flexible initialization and entity registration. Collectively, these constitute a rare combination of features. The infrequency of these features existing together reduces the likelihood of factories being a desirable seam for testing. Here are some recommendations for creating your factories to better support testability.

Because of the testability concerns with singletons in general, you should try to implement your factories as singletons by convention rather than by implementation. Ensure by the way they are constructed that only one instance exists. Many dependency injection frameworks provide mechanisms to support singletons by convention.

A useful factory implementation for testing only needs to support either flexible initialization or dynamic registration. With sufficiently flexible initialization, you can create almost any construction of the entities you wish by changing the initialization parameters. With dynamic registration, you can register the builders or templates to create exactly the right entities. Personally, I prefer dynamic registration over flexible initialization, simply because of the argument presented previously that flexible initialization somewhat defeats the purpose of a factory. That argument does not hold as strongly, however, when flexible initialization supports the creation of more complex networks of entities.

A factory makes a good seam when trying to test a component that uses the factory to generate collaborators. The ability to modify the initialization of generated entities or to register alternate implementations allows you to inject behavior into the software under test through the altered implementations.

While this seems like a clean way to affect the behavior you are testing, it comes at a cost. If you added the factory simply to support testing, a common maneuver for ardent mockists,12 you are adding code and complexity that itself needs to be tested and maintained. Such a move should have strong justification for the cost. Additionally, factories are typically implementation details; they are a means to an end, not a requirement of the software. As such, using a factory as a seam couples your test to the implementation. Additionally, the collaborators created by the factory are also frequently implementation details that couple the test at least to an interface or template, if not a full-on implementation. Both of these vectors for coupling inhibit the scalability and maintainability of your test regimen. Configuring factories produces looser coupling than using the implementation classes generated by the production factory when injecting behavior, but higher coupling than avoiding the factory entirely.

12. Arlo Belshee wrote an insightful blog post about the mocks versus no mocks debate at http://arlobelshee.com/post/the-no-mocks-book that includes an example of creating a factory exclusively for mock injection during testing.

Factories are useful test seams, especially when testing with a behavioral flavor using mocks or other forms of test double. You should approach the additional coupling and complexity that factories can introduce with informed caution, which is why I choose to put them low on the list of seams to exploit.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.120.57