Table of Contents

Making Automated Tests Better by Using the Strategy Design Pattern

Well-worked software testing makes software development successful. And automated tests represent a valuable concept (one of many) of software testing techniques.

Extensible automated tests are difficult to write. Whenever you create a new test to verify a more and more complex use case scenario, you’ll face more and more difficulties. To simplify maintaining automated tests you can actually use the same software design patterns that we benefit from when we implement the business logic. One such pattern is called a  Strategy Design Pattern, which can help us write code that’s extensible and highly maintainable.

Strategy design Pattern

As we can see, there’s one main interface, and other classes must only extend this interface. Those other classes (the three small blocks on the left in the diagram) are necessary to define more specific methods that will be available to the context object. The context object will run the main strategy (the main class) that will call a respective sub-strategy depending on context.

When we implement a strategy design pattern, the interface we’re going to build will let us define the behavior of a testing algorithm at runtime.

The following section will give out a Java-based example for how to implement an automated test based on a strategy design pattern. Using automated testing when developing web projects is very important, and automated testing can be greatly improved if we follow software design patterns.

Implementing Strategy Design Pattern for an Automated Test

Any website has different types of users such as the administrator, a new user, and a registered user, and we have to test each of them. We can write automated tests that cover each type of user. But this leads to a problem as we’ll write a lot of boilerplate code. Because each type of user has own access rights, we have to write more specific tests to validate specific user rights. Then, what if a new type of user appears? Do we have to re-write the entire test case? Actually, with the help of strategy design pattern we can implement tests in a better way.

To write automated tests with the strategy design pattern in mind, we’ll need a base Java interface that will expose an public function. This interface will be called IValidationStrategy, and it will implement the main interface. The IUserValidationStrategy interface looks like this:

// Strategy Design Pattern
public interface IValidationStrategy {
  AdminValidationStrategy adminValidation;
  NewUserValidationStrategy newUserValidation;

  public void adminValidation() {
	adminValidation.validate();
  }

  public void newUserValidation() {
	newUserValidation.validate();
  }
}

As we can see, this interface starts with the “I” letter to notify that this class is actually an interface.

As we mentioned in the introduction, the main interface won’t really test anything. Our IValidationStrategy interface can, for example, raise an error if its method is called directly. In such a way, we notify other developers that they must write own automated test for a specific strategy. This basically means that we need to create own methods in specific strategies (other Java classes).

Our interface – IValidationStrategy – defines two public classes AdminValidationStrategy and NewUserValidationStrategy. The classes each define the validate() method specific for these interfaces. Certainly, an interface can expose other public methods if necessary. Again, what’s important is to follow the strategy design principle and write all specific (read: custom) test logic in respective classes (sub-strategies).

The two following code snippets are examples of public interfaces – sub-strategies. The first snippet is designed to test validation of an administrator, while the second snippet will test the validation of a new user:

// Specific Strategy
public class AdminValidationStrategy implements IValidationStrategy {
  adminValidation() {
    validate() {
      // custom implementation
      // test admin validation here
      System.out.println('Admin is tested');
    }
  }
}
// Specific Strategy
public class NewUserValidationStrategy implements IValidationStrategy {
  newUserValidation() {
    validate() {
  	// custom implementation
  	// test admin validation here
  	System.out.println('New user is tested');
    }
  }
}

As we can see, the AdminValidationStrategy and NewUserValidationStrategy classes must inherit from the IValidationStrategy. What these classes actually do is they extend the main interface by adding specific behavior depending on what class will be called by the context class. We have to redeclare methods (the validation() method in our case) in these classes.

Then there’s context, which depends on the user validation strategy interface. The context object must provide respective data to the IValidationStrategy class so it could check rights of a specific user:

// define context
public class UserValidationContext {
  private IValidationStrategy strategy;
  // use the strategy here
  IValidationStrategy user = new TestUser();
  user.validate() {
	System.out.println("New user is tested.");
  }
}

Within the UserValidationContext class, we need to instantiate a user (an administrator or a new user) and call the respective method (test_user_validation in our example).

Whenever you implement a new user role for your application, you don’t need to change the context (a new user or an admin) in which the code runs. It’s only necessary to implement a new strategy for a new functionality, and use the exposed interface with that strategy.

Such approach helps reduce the boilerplate code as the main test scenario only implements the basic logic for all types users. The logic that can change (for example, when the same type of user can get new rights) is encapsulated and tested in additional classes. The bottom line, if you implement the strategy design pattern for automated testing, it’ll be simpler to extend and support your automated tests in the future.

Author : Sviatoslav Andrushko

Sviatoslav is a technical writer at RubyGarage and is looking forward to new technologies in web development. Sviatoslav is eager to learn patterns and approaches in web development and likes to share the acquired knowledge with others.

Selenium Interview Questions Part-2
Selenium Interview Questions Part-2
Previous Article
Page Object Model
Page Object Model
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback