In my articles from the series “Design Patterns in Automated Testing“, I am sharing with you ideas how to integrate the most useful code design patterns in the automation testing. In my last publication, I explained to you how to create an extendable test execution engine for Web Driver utilizing the classical implementation of the Observer Design Pattern. Here I am going to show you another more advanced implementation of the Observer Design Pattern using the power of the .NET’s events and delegates.

UML Class Diagram

Participants

The classes and objects participating in this pattern are:

ITestExecutionProvider – Objects use this interface to register as observers and also to remove themselves from being observers.

– Objects use this interface to register as observers and also to remove themselves from being observers. 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. TestExecutionEventsArgs – 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 concrete observer can be any class that implements the BaseObserver class. Each observer registers with a particular provider to receive updates via subscribing to the provider’s events.

– A concrete observer can be any class that implements the BaseObserver class. Each observer registers with a particular provider to receive updates via subscribing to the provider’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.

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.

You can find more information about the classical implementation of the Observer Design Pattern in my previous article- “Observer Design Pattern- Design Patterns Automation Testing“. If you compare the UML diagrams of the classical implementation and the events based one, you will probably notice that they are almost identical. One of the changes is the absence of the ITestBehaviorObserver interface. Nearly all of the other changes are located in the provider or as previously named subject class. (The two names- subject and provider are possible) The provider’s interface now contains only events that are used by the concrete observers to subscribe to various update points. Also, the provider doesn’t hold any Subscribe and Unsubscribe methods. Instead, events are used.

Now the interface for the provider class in this implementation of the Observer Design Pattern looks like the code below.

The concrete provider looks almost identical to the previously developed with minor changes.

In the different test execution points, the method RaiseTestEvent is used to notify all subscribed observers for that particular execution point. If there are not any subscribers, the event is not triggered. The concrete observer’s needed information is passed by the creation of a new object of type TestExecutionEventArgs.

It only contains two properties. The MSTest TestContext and the MemberInfo which is the reflection information about the currently executing test method.

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.

Create Base Observer Using .NET Event and Delegates

As I have already pointed in the Events based implementation of the Observer Design Pattern, the base observer class doesn’t need to implement any interfaces.

In the Subscribe method, the concrete observer is subscribed to all available provider’s events. However, the wired methods are empty. This gives the specific child observer the flexibility to override only the needed methods. These parent methods are marked as protected so they cannot be put in an interface.

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 Concrete Observers Powered by Attributes

The primary goal was to create a way so that the user to be able to control the current test’s execution browser type through attributes. Below you can see that the usage of the BaseTest class and the ExecutionBrowser attribute didn’t change.

The test execution flow stays intact. The only change in the concrete observers is that the overridden method should be marked as protected instead of as public.

The code for controlling the browser type is almost identical with only the previously mentioned difference.

Putting All 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.