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. This type of integration brings more maintainable and extendable code through the following of the SOLID principles. Most of the techniques follow the Open Close Principle where the code should be open for extension but closed for modification. I am going to use this principle in the current publication heavily. I am going to explain to you how to create an extendable test execution engine for Web Driver utilizing the classical implementation of the Observer Design Pattern. I am going to present to you even better implementations using .NET built-in event\delegates and one with IObserver<T>. You will be able to find them in the next Advanced Observer Design Pattern article.



Definition Strive for loosley coupled designs between objects that interact.

Allows you to send data to many other objects in a very efficient manner.

No modification is need to be done to the subject to add new observers.

You can add and remove observers at any time.

The order of Observer notifications is undependable. The Observer Design Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

UML Class Diagram

Participants

The classes and objects participating in this pattern are:

ITestExecutionSubject – 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. MSTestExecutionSubject – The concrete subject always implements the ISubject interface. In addition to the attach and detach methods, the specific subject implements different notification methods that are used to update all of the subscribed observers whenever the state changes.

– The concrete subject always implements the ISubject interface. In addition to the attach and detach methods, the specific subject implements different notification methods that are used to update all of the subscribed observers whenever the state changes. ITestBehaviorObserver – All potential observers need to implement the observer interface. These methods are called at the different points when the subject’s state changes.

– All potential observers need to implement the observer interface. These methods are called at the different points when the subject’s state changes. OwnerTestBehaviorObserver – A concrete observer can be any class that implements IObserver interface. Each observer registers with a specific subject to receiving updates.

– A concrete observer can be any class that implements IObserver interface. Each observer registers with a specific subject to receiving updates. BaseTest– The parent class for all test classes in the framework. Uses the TestExecutionSubject 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.

With the Observer Design Pattern, the Subject is the object that contains the state and controls it. So, there is one subject with a state. The observers, on the other hand, use the state, even if they don’t own it. There are many observers, and they rely on the Subject to tell them when its state changes. So there is a relationship between the one Subject to the many Observers.

The first step to the integration of the Observer Design Pattern in the automation test framework is to create the ISubject interface.

The first two methods Attach and Detach are used by the observer classes to associate themselves with the subject. The rest of the interface’s methods are called in the different steps of the test execution workflow to notify the observers about the changes in the state of the subject.

In order the subject to be able to notify the observers, they need to implement the IObserver interface where all notification methods are defined.

After that, a concrete subject class should be created.

The specific subject knows nothing about the particular implementations of the observers. He is working with a list of ITestBehaviorObserver. The Attach and Detach methods add and remove observers to/from the collection. In this classic implementation of the observer design pattern, the observers are responsible to associate themselves with the subject class.

For the current use case, not all of the observers need to implement all of the notification methods. For example, the observer for the Owner attribute needs to execute code only for PostTestCleanup. In order to support this requirement, we are going to add a base class that is going to implement the ITestBehaviorObserver interface.

As all notification methods are empty, the child class needs only to override the necessary ones. Also, the base class constructor requires a ITestExecutionSubject parameter in order to be able to associate the current observer to the subject.

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

Configure Test Execution Browser with Attribute

Now it is time to utilize all these classes to solve some practical problems. The primary goal is to create a way so that the user to be able to control the current test’s execution browser type through attributes.

In the above example, the new attribute is used to configure the test engine to use the Chrome browser for all tests in the class. However, the test level attribute is going to override the class level one. So for the SearchTextInSearchEngine_First_Observer test the Web Driver browser is going to be set to Firefox.

There is nothing special about the ExecutionBrowserAttribute, it only holds a property of the enum BrowserTypes.

This attribute is configured to be available on test and class level through the AttributeUsage attribute.

The logic that extracts the current values of the new attribute and the configuration of the WebDriver engine is implemented in a new concrete TestBehaviorObserver.

The values from the attributes are extracted via Reflection.

The current observer uses the singleton class Driver to access the Web Driver configurations. In the PreTestInit phase, it tells the driver to start a new browser instance of the specified browser type. In the PostTestCleanup it calls the same class to stop and dispose the browser instance.

Throw a New Exception if There Is No Owner Attribute Set

The second observer class part of the observer design pattern is going to fail the current test if the Owner attribute is not set.

Again the information about the test’s attribute is retrieved via Reflection. The above concrete observer is overriding only the PreTestInit method. If the method detects in this phase that there isn’t such attribute, a new exception is going to be thrown.

Extendable Test Execution in BaseTest via Observer Design Pattern

All of the previously mentioned logic should be combined together. The job is handled by the BaseTest class which is the parent class for all tests.

If the test classes need to add its own TestInit/TestCleanup logic, they need to override the TestInit/TestCleanup methods, the TestInitialize/TestCleanup attributes should not be used. In the base CoreTestInit method first are executed the PreTestInit methods of all observers with the help of the current subject class. After that is executed the TestInit method or its overridden version. Finally, all observers PostTestInit methods are executed. The same flow is valid for the cleanup methods. In the InitializeTestExecutionBehaviorObservers are created the instances of all desired observers through passing them the current subject as a parameter. After the base constructor is executed the TestContext property is populated from the MSTest execution engine. It is used to retrieve the currently executed test’s MemberInfo.

If needed similar methods can be created for the class level initializations and cleanups.