Sikuli ScreenObjects Part 1 - OOP Tests Design

    Object Orient Programming model is a well proven concept. Following the principles described by that model will result in more quality code. It will introduce clarity and its modular approach to data will improve code maintainability. Here I will attempt to demonstrate my take on applying OOP principles to automated tests design using Sikuli.

    While doing Test Automation one comes across multiple challenges, like choosing the most appropriate tools for the job and writing the actual code while struggling with application specific technical difficulties

    One additional challenge that sometimes goes unnoticed until it becomes a problem during more advanced stages of the automation process, is the maintenance of the existing code. Specifically when adding new flows to an already existing scenarios with only slight changes.

    For instance, think of a desktop application that consists of three screens. Now consider two following possible scenarios where first two steps are completely similar and the last two steps are different.

Example Scenario 1:
  1. Open Screen 1
  2. Fill some fields
  3. Click Button 1
  4. Verify that Screen 2 appears
Example Scenario 2:
  1. Open Screen 1
  2. Fill some fields
  3. Click Button 2
  4. Verify that Screen 3 appears
    From the above example, you can see that the scenarios are definitely different but they do have a  a shared part. So at this point, the most straight forward thing to do will be to copy that part of Scenario 1 which is similar to the first two steps of Scenario 2 (first two steps) and use it in Scenario 2 respectively.
    Clearly that solution might seem the easiest at first, however it will introduce two problems in the future, as the amount of code and test scenarios will increase:
  • Unneeded increase in the amount of code
  • Resulting support difficulties
    Even if we ignore the increasing amount of code issue, continuous support difficulties will present a serious problem very soon.
    Imagine that you have as few as only ten test cases with some shared functionality. If for some reason the application you are testing has changed (and it will happen sooner or later), you will need to manually amend the shared functionality block for each one of all ten scripts! Of course, as the number of tests increases, the amount of modifications that will need to be maintained will increase significantly and eventually the code maintenance will become practically unfeasible.

    The other way we can tackle this problem is by following a modular approach. If we utilize the OOP principles we can come up with following definitions:
  • Encapsulation
    Every segment of the application should be seen as an independent logical unit. Then this unit can be implemented as a Class. Every piece of functionality in this unit, can be implemented as a class method of that Class.
  • InheritanceWhen we define and implement all relevant part of the application that we are testing, we can just use the existing classes and methods to build end-to-end scenarios without being concerned about the implementation
Let us define some basic terminology that I will use:
  • Application - the visual side of the application, the way it physically looks on the screen
  • Screen - Current application physical appearance. The application may have different areas, each one of these areas is a screen.

Practical example of application mapping concept

    So the first step that we do before we start the mapping of the application we need to test is to open it, navigate through its screens (if there are any of course) and try to divide the application into logical partitions as discussed above. 

    It is important to remember that there is not just one correct way to map an application. This is just our way to map the application the way it will be more convenient for us to work with it. So if, you come across a very complex application with many areas on the same screen where each area is responsible for a separate logical function you may decide to split a single screen into multiple classes.

    So let's start with a very simple application.

    When we launch Windows calculator, we get the following screen:


    Needless to say that is a very basic looking application and we can quite confidently define almost the whole window as one screen. Why almost? Because of the menu on top. I usually tend to define menus like this as a separate class as they perform a different logical function. So based on that decision we get three classes:

  • Main window class - this the whole window, including the exit/minimize/maximize buttons, menu bar, calculator buttons and the display.
  • Menu bar class - this is just the menu bar on top that includes "View", "Edit" and "Help" menus.
  • Operational area class - this is the operational area of the application, the calculator buttons and the display
Windows calculator main window split into logical areas

So the very basic classes that will define the above areas might look something like that:

Main window class:

class MainWindow(object):
    def __init__(self):
        pass

Menu bar class:

class MainWindowMenuBar(MainWindow):
    def __init__(self):
        pass

Operational area class:

class MainWindowOptionalArea(MainWindow):
    def __init__(self):
        pass

    At this stage these classes are not very helpful but they will grow and become more useful as we progress.

    In the next post we will start the functionality coverage of the application.

Comments