Design patterns have high importance for building cost-efficient products with high-degree of reusability and based on component oriented models. Design patterns provide abstraction and robust platform for reusable s/w design. My intention is to think over what existing design patterns fit to automated testing. Let’s do this!
As a fan of Web 2.0 and Wikipedia, I’ll refer on definitions and articles by linking to Wikipedia pages. See full list of design patterns on dedicated page. If you need to check details on a particular pattern, just click on appropriate link in Table listing all patterns within section “Classification and list”.
Creational patternsAbstract factory. This is a proper mechanism of building abstraction layer for derived object types. For instance, it may be useful for implementation a framework layer responsible for working with different control types (e.g. MFC controls, pure Java controls, .Net controls,…) but operating as a single interface.
Builder pattern can be employed on test data construction and as a helper in many cases. Also you can use this approach for test suite initialization, stand preparation
Factory pattern can be used in any context for simplification object instantiation. There are a lot of places where you can fit this pattern for auto testing (dynamic and static test data instantiation; logging, reporting, test stand objects, etc)
Lazy initialization can be used to reduce expenses of keeping objects in memory. The best way is to combine this approach with object clean up once it no longer is being used.
Prototype as creational pattern simplifies object instantiation and avoids sub classing like in abstraction factory model
Singleton is a protected method of keeping only one object instance in memory. Where can be used: all objects which should follow through whole test cycle or round, for example, logging and stack trace, high-level test data, environmental data, 3rd party objects initialization to keep resources. If an object is dynamic one, you have to provide special interfaces like update(), rollback(). Also this pattern is proper way for developing high-performance models, optimization resource allocation and expenses and in environments with weak or absenting garbage collection and memory clean up.
Structural patternsAdapter or wrapper can be used anywhere for resolving data compatibility and interface simplification. Simple and basic pattern
Composite patterns can be used for representation complex object like current test data set in a tree model (one to many relationships). I prefer to rely this approach on XML test data presentation as structured object model
Decorator is proper way to extending functionality without affecting original code. I suggest to use it as helper or quick adding workaround s and backdoors
Proxy as intermediate level for access control. I’m not sure about usage context in test automation but as this is essential one, I include this to the list. Who knows, maybe this guy can be used in some specific tested applications.
Facade pattern. I like to use this pattern for managing test data through uniform interface so that I don’t take care about used test data native. All specific code of data native processors placed somewhere inside, while decorator simply returns an object. Very handy.
Behavioral patternsChain of responsibility is a proper pattern for designing own logging and stack trace
Command pattern. It is extremely valuable for building keyword-driven test automation frameworks where provided interface operates with macro languages. Macro is a composite state which implements completed and composite User step which is actually intermediate level between granular steps and completed workflow (like Use case). The whole workflow (e.g. Use case) is being implemented in test scenario designed from a certain macros (steps).
Another usage of this pattern is testing transactional logic by mirroring some part of transactional model of application itself on test code.
In joint use with Abstract factory, you can build a layer for typed control of mixed technologies. In my practice, I build object loader and abstracted invoking object properties and methods for supporting different COM object versions at fly. You can go ahead and implement similar abstraction for different technologies, plus empower your design by invention composite commands for batch controls processing. For example, wizards processing by invoking meta-commands (like “set up default settings”)
Interpreter can be used to simplify working with custom string patterns. It’s really useful for substituting using predefined templates and for running code pieces using Eval() method
Iterator is essential for handling corresponding controls, like grids, tables, custom lists. Basic ally, iterator should have first(), last(), next(), add(), remove(), isLast() methods.
Null object is a basic and helpful approach of default value implementation. I can state – this simplifies routine test development.
Observer pattern. I advice to be hand on with this guy especially for testing AJAX applications and other ones which are asynchronous in nature. This pattern can be used in designing event-based test auto9mation frameworks.
State pattern. I did not use this one, though I believe it’s a basis of behavior-driven test frameworks
Strategy pattern can serve for switching algorithms using polymorphism or reflection (btw, JS implementation is really fun). The Strategy perfectly correspond with Open/Closed principle
Template method is a generic for designing reusable code (not only object-oriented) with overriding. I’d like to try this template to implement advanced test data engine.
I intentionally left TDD patterns out of this scope, since they are really specific ones, moreover I tried to highlight them (stub, fixture, fake, mock, object mother, object registry, assertions) in a separate post. Finally, most of the mentioned patterns are implementable in all modern programming languages (both OO and scripting, like JS, VBS) .
Well, enjoy designing patterns and inventing your own!