The “Design Patterns in Automated Testing” series are all about the integration of the most practical design patterns in the automation testing. Last two articles from the sequence were dedicated to the Observer Design Pattern. The first one was about the classic implementation of the pattern and the second one about its events-delegates substitute. There is a third possible implementation of the observer design pattern that is a new one for .NET. It uses the IObserver and IObservable interfaces. This last article dedicated to the observer design pattern is going to look into this new implementation.

UML Class Diagram

Participants

The classes and objects participating in this pattern are:

ITestExecutionProvider – Contains primary method definitions that every execution provider should implement.

– Contains primary method definitions that every execution provider should implement. MSTestExecutionProvider – The concrete provider/subject always implements the IProvider interface. Тhe particular provider holds different notification methods that are used to update all of the subscribed observers whenever the state changes.

– The concrete provider/subject always implements the interface. Тhe particular provider holds different notification methods that are used to update all of the subscribed observers whenever the state changes. ExecutionStatus – The object that is used to transfer the state of the provider to the concrete observers.

– The object that is used to transfer the state of the provider to the concrete observers. BaseTestBehaviorObserver – All potential observers need to inherit the base observer class. Additionally to the Subscribe and Unsubscribe methods, it holds empty methods that can be later overridden by the concrete observers.

– All potential observers need to inherit the base observer class. Additionally to the and methods, it holds empty methods that can be later overridden by the concrete observers. OwnerTestBehaviorObserver – A particular observer can be any class that implements the BaseObserver class. Each observer registers with a particular provider to receive updates via subscribing to the supplier’s events.

– A particular observer can be any class that implements the BaseObserver class. Each observer registers with a particular provider to receive updates via subscribing to the supplier’s events. BaseTest – The parent class for all test classes in the framework. Uses the TestExecutionProvider to extends its test execution capabilities via test/class level defined attributes and concrete observers.

– The parent class for all test classes in the framework. Uses the TestExecutionProvider to extends its test execution capabilities via test/class level defined attributes and concrete observers. Unsubscriber– Object that is used to healthy dispose observers when they go out of scope.

Observer Design Pattern C# Code

Use Case

The primary goal of the sample code is to provide an easy way to automation engineers to add additional logic to the current test execution via class/test level attributes. For example configure current test execution browser or fail the test if the owner attribute is not set.

The following class structure is going to be used.

One of the differences between the classic implementation and the IObservable one is that the TestExecutionProvider doesn’t hold Unsubscribe/Detach method. Next there is a big difference in the implementation of the Subscribe method. The new implementation uses a new class called Unsubscriber which task is to healthy release any Observer that goes out of scope.

The Unsubscriber is a generic class that implements the IDisposable interface. It takes care of the removal process of the concrete observer from the provider’s collection. In the other implementations of the Observer Design Pattern, when an observer goes out of scope you might think that its memory will be cleaned by the Garbage Collector. However, if its reference held in the provider is not properly released, the GC will wait until the supplier goes out a scope to clean the observer’s memory. The implementation of the IObserver and IObservable interfaces prevents it.

While ago when we were working on the first version of the BELLATRIX test automation framework, I did this research and afterward we used a similar approach in many of the features of the solution.

Notification Methods Exposed by IObserver Interface

The another big difference in this implementation is that the observers interface IObserver presents only three public methods to the concrete provider- OnNext, OnError, and OnCompleted.

OnNext– The provider calls this method to send notifications to the subscribed observers.

OnError– This method notifies the observers that an error happened in the reported data. Not necessary means that an exception occurred. It should be seen as informational, the provider should not expect the observers to provide an error handling.

OnCompleted– Reports that no further data is available.

To be able to support multiple notification points with different behavior, we use the ExecutionPhases enumeration to notify the particular observers for the current execution status. This enum’s reference is held in the object that is used to pass notification data between the provider and its observers- ExecutionStatus.

It holds three properties- the MSTest TestContext object, reflection MemberInfo object containing an information about the currently executed test method and the current execution phase.

There are five possible execution phases.

The provider calls the OnNext method of each subscribed observer in the specific notification points, passing a new instance of the ExecutionStatus data object.

For more detailed overview and usage of many more design patterns and best practices in automated testing, check my book “Design Patterns for High-Quality Automated Tests, C# Edition, High-Quality Tests Attributes, and Best Practices“. You can read part of three of the chapters:

Defining High-Quality Test Attributes for Automated Tests

Benchmarking for Assessing Automated Test Components Performance

Generic Repository Design Pattern- Test Data Preparation

Create Base Observer Using IObserver Interface

The base observer class implements the IObserver<ExecutionStatus> interface. It requires the implementation of the previously mentioned three methods- OnNext, OnError, and OnCompleted. However, the class holds more important methods like Subscribe and Unsubscribe. Also, exposes empty protected virtual methods to its childs for the different notification points like PostTestCleanup and PreTestInit.

The Subscribe method accepts a provider instance as a parameter and calls its Subscribe implementation to attach itself. The Unsubscribe method only calls the Unsubscriber’s Dispose method where the observer is removed from the provider’s observers collection.

The base OnNext method performs different actions based on the current execution phase. The default behavior is that if the child behaviors don’t override the empty implementations of the pre and post methods, nothing will happen. With this mechanism in hand, the concrete observers can implement only the needed notification point methods not all of them.

The only difference compared to the other implementations of the Observer Design Pattern in the concrete observer is that the Pre and Post methods are marked as protected.

Assemble Everything Together in BaseTest Class

Through the usage of separate classes for the implementation of the pattern, there are almost no changes in the BaseTest class. Only the implementations of the concrete provider and observers are replaced. Although it is possible to attach an observer to multiple providers, the recommended pattern is to connect an IObserver<T> instance to only one IObservable<T> instance.