Performance testing using the observer pattern

In terms of behavioral design patterns applicable in automation testing, our next target is the observer. What is this? How should we apply it in automation? Well, after investigating different valuable scenarios, we’ve reached to the conclusion that it could have a huge impact in terms of performance testing. How so? Well we measure for example the CPU usage, and based on the observer a notification could be received when a spike is detected.

What is this?

The observer pattern states in defining a one to many dependency between different objects and if the state of an object is changed, all the others are notified.

Performance testing scenario?

Define a base object which measures the CPU usage. All the tests are linked to it and if there is a spike during the test execution, a notification will be automatically raised. This could have a huge impact for everyone interested on testing their application performance.

Implementation

Requirements

  • Python 3
  • Pycharm IDE
  • CHROME driver
  • psutil –
    """psutil is a cross-platform library for retrieving information on
    running processes and system utilization (CPU, memory, disks, network,
    sensors) in Python. Supported platforms:
    
     - Linux
     - Windows
     - OSX
     - FreeBSD
     - OpenBSD
     - NetBSD
     - Sun Solaris
     - AIX
    
    Works with Python versions from 2.6 to 3.X.
    """

Using psutils package we can get different system information like CPU usage, memory consumption, etc. For this tutorial we are intersted on highlighting the CPU usage. Below there is a function which filters all the processes and get the Pycharm specific one. In case a test is running, the below function will return the its usage.

When *interval* is > 0.0 compares process times to system CPU
times elapsed before and after the interval (blocking).

def get_process_info_spike(process):
    """
    :param process: get system information like memory consumption, cpu usage
    :return:
    """
    for process_id in psutil.pids():
        p = psutil.Process(process_id)
        if p.name() == 'pycharm':
            if process == 'memory':
                return p.memory_percent()
            elif process == 'cpu':
                return p.cpu_percent(interval=1)
            else:
                return p

Step 1 – Define the Process class (the Subject)

The entry point of the observer pattern is the Process class definition. It’s actually the spot where we define the business logic. It is also has two important responsibilities:

  • Keep a track of the observers (subscribers)
  • Send a notification to the subscribers if there is a change in terms of behavioral changes)
class Process:
    """
     - is aware of observers
     - send a notification to the observers if its state is changed
    """

    def __init__(self):
        self._observers = set()

    def subscribe(self, who):
        """

        :param who: method used to register the tests which will be notified while running performance testing
        """
        self._observers.add(who)

    def un_subscribe(self, who):
        """

        :param who: method used to un-subscribe the tests which will no longer be notified by the performance measurements
        """
        self._observers.discard(who)

    def dispatch(self, test_func, message):
        """

        :param test_func: test to be notified by the performance measurements
        :param message: system information measurements
        :return:
        """
        for subscriber in self._observers:
            if get_process_info_spike(message) >= 50:
                subscriber.update(test_func, 'CPU usage warning: ' + str(get_process_info_spike(message)))
            else:
                subscriber.update(test_func, 'CPU usage normal: ' + str(get_process_info_spike(message)))

Step 2 – Observant class

Below we will define a class which will observe the Process changes.

class Tests:
    """
    Define the observant class
    """
    def __init__(self, name):
        self.name = name

    def update(self, test_func, message):
        test_func()
        print('{} test measurement - "{}"'.format(self.name, message))

Step 3 – A simple test

There is one more step to be done, writing a test case. For this one we will reuse an existing test defined in the page object tutorial. Here we perform a search on Wikipedia, perform a login, a search and, that’s it.

def search_test():
    driver = get_selenium_driver('CHROME')
    driver.get("https://en.wikipedia.org/wiki/Main_Page")
    main_page = HomePage(driver)
    main_page.login()
    main_page.search()
    driver.quit()

Step 4 – Testing

The last part, but not least, let’s check this pattern. First we create a process object, aftewards define an observant ‘test_search’, subscribe it to the Process class and in the end we notifiy the test to get the CPU measurement.

 if __name__ == '__main__':
    process = Process()
    test_search = Tests('Search')
    process.subscribe(test_search)
    process.dispatch(search_test, 'cpu')

Step 5 – The output

The outcome of this test is the Process notification of the CPU usage.
See below the actual result:

Search test measurement - "CPU usage normal: 8.7"

Step 4 – Conclusions

In conclusion, the observer pattern has it’s utility also in automation testing. This is just a simple example on how to use it based on measuring the CPU usage, but it can be easily extended to other useful testing procedures.

More details about the implementation could be found here and for more details feel free to contact us.

One thought on “Performance testing using the observer 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.