Test case life cycle based on state pattern

Going further with our research on different design patterns used on automation testing, we’ve made a stop around the state pattern. As any developer knows, this one is part of the behavioral family.
For testers maybe it’s a new concept, so as a short notice, behavioral patterns are responsible for setting up a communication between objects.
State pattern provides different behaviors based on the internal object state. In this article, our purpose is to find an applicability in test automation. So what about the life cycle of a test? A simple scenario would be:

  • Start the test
  • Execute different steps
  • Stop the test

We’ve just listed three states, of course, that there could be more but to get a simple understanding of the state pattern that’s enough. How we accomplish this? Just follow the implementation.

Implementation

Requirements

  • Python 3.6
  • Selenium Webdriver

Step 1 – State manager

First, we need a manager. This acts as an interface to the client and provides the actual state of the object.

class Manager:
    """
    State machine manager.
    Acting as an interface to the client and providing the actual state of the object
    """
    def __init__(self, state):
        """
        :param state: current object state
        """
        self._state = state

    def get_state(self):
        """
        :return: state getter
        """
        self._state.run()

Step 2 State interface

Secondly, there is a state interface, and get_statemethod will be implemented by each sub-class (reflecting specific states)

class State(metaclass=abc.ABCMeta):
    """
    Interface definition for behaviour encapsulation
    """

    def __init__(self):
        self._driver = get_selenium_driver('chrome')

    def get_driver(self):
        return self._driver

    @abc.abstractmethod
    def run(self):
        pass

Step 3 – Actual states

Going further, you can find three states implemented.

class StartTest(State):
    """
    Prepare the test execution environment
    """

    def run(self):
        print(" Start test state!!! ")
        self.get_driver().get('https://en.wikipedia.org/')

class ExecuteTest(State):
    """
    Run run different test steps
    """

    SEARCH_BUTTON = 'searchButton'

    def run(self):
        print(" Execute test steps state!!! ")
        if self.get_driver().find_element_by_id(ExecuteTest.SEARCH_BUTTON).is_displayed():
            print("Search button available")
            self._driver.find_element_by_id(ExecuteTest.SEARCH_BUTTON).click()
        else:
            print("Search button not available")

class StopTest(State):
    """
    Close the testing session
    """
    def run(self):
        print(" Stop test state!!! ")
        self.get_driver().quit()

Step 4 – Testing

How all those works together? First, we instantiate the states which we want to have for our test (start, execute and stop), next we will pass the instance to the manager, so in the end, it will get each state for our object.

if __name__ == '__main__':
    start = StartTest()
    execute = ExecuteTest()
    stop = StopTest()
    for test_state in [start, execute, stop]:
        manager = Manager(test_state)
        manager.get_state()

The output will be:

Start test state!!!
Execute test steps state!!!
Search button available
Stop test state!!!

Conclusions

Using state design patterns facilitates the test case lifecycle definition, having each state clearly separated, but controlled at the same time by a manager. The only downside which we’ve noticed here is the necessity to instantiate the manager each time when we want to create a new state. The applicability could be also extended like adding different dependencies between the states so we will leave it up to your imagination to come with those scenarios.
More details about the implementation could be found here

One thought on “Test case life cycle based on state pattern

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.