UI automation test framework design and PageObject transformation!

During the UI automation testing process, faced with complex business scenarios, we often encounter the following challenges:

  • Simple recording/playback is fast, but cannot adapt to complex scenes;
  • Writing automated test scripts is more flexible, but the workload is heavy and maintainability is poor;
  • The previous encapsulation technology (PageObject) can adapt to various UI scenarios, but its structure is loose and cannot be migrated across multiple projects;

Therefore, testing teams often also need a custom testing framework to compensate for the shortcomings of the existing framework.

Test framework encapsulation idea

Since the UI automated testing framework is used around the UI interface, the PageObject design pattern is still used to encapsulate the UI and tests. At the same time, it cooperates with the Pytest unit test to effectively organize and apply the scripts coherently, thereby improving the maintainability and readability of the framework. sex.

Since the test framework is based on the PageObject design pattern, the main directions are PO improvement, data-driven, exception handling, etc., such as:

  • Data-driven test data: store data in external yaml files and use yaml tools to read data;
  • Data-driven data steps: Put the operation steps into an external yaml file, use the yaml tool to read the operation steps, and use special functions to parse and implement the operation steps;
  • Automated exception handling mechanism: Encapsulate and improve the element search module, including how to handle pop-up windows;

Page_Object Transformation

As a general UI testing framework, PageObjet is not only suitable for web automated testing, but also Appium mobile automated testing. Its advantages are as follows:

  • Reduce code duplication
  • Improve test case readability
  • Improve test case maintainability

PO transformation example (based on Snowball App)

This case will encapsulate and improve Snowball App with Page Object.

When you start the Snowball App, you will enter the homepage. Click the search box to enter the search page, search for a stock and determine whether the stock price is greater than 200:

The module relationship of PageObject is as follows. All modules must inherit BasePage. App implements operations such as starting, restarting, and stopping. Main implements operations such as entering the search page and entering the stock page:

Now I have also found a lot of test friends and created a communication group to share technology, sharing a lot of technical documents and video tutorials we collected.
If you don’t want to experience the feeling of not being able to find resources when studying on your own, having no one to answer your questions, and persisting for a few days before giving up.
You can join us to communicate. And there are many technical experts who have made certain achievements in automation, performance, security, test development, etc.
Share their experience, and also share many live lectures and technical salons
You can learn for free! Focus on it! Open source! ! !
QQ group number: 110685036 [password: csdn999]

The base_page module is the parent class of all page classes, which defines public methods. For example, after encapsulating the find method below, subclasses can call find:

from appium.webdriver.webdriver import WebDriver

    _driver: WebDriver

    def __init__(self, driver: WebDriver = None):
        self._driver = driver

    def find(self, locator, value: str = None):
        #If a tuple is passed in, just use one parameter: locator
        if isinstance(locator, tuple):
            return self._driver.find_element(*locator)
            return self._driver.find_element(locator, value)

The App module encapsulates the app’s startup, restart, stop and other methods. When the app starts, it will enter the main page, so the main method below must return Main. The definition of the Main class will be explained later:

from appium import webdriver
from test_appium.page.base_page import BasePage
from test_appium.page.main import Main

class App(BasePage):
    #Specify the package name and activity name of the app
    _package = "com.xueqiu.android"
    _activity = ".view.WelcomeActivityAlias"

    def start(self):
        #Initialize if driver is empty
        if self._driver is None:
            caps = {}
            caps["platformName"] = "android"
            caps["deviceName"] = "hogwarts"
            caps["appPackage"] = self._package
            caps["appActivity"] = self._activity
            caps["noReset"] = True
            #Initialize driver
            self._driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        #If the driver is not empty, start the activity directly
            self._driver.start_activity(self._package, self._activity)

        return self

    def restart(self):

    def stop(self):

    def main(self) -> Main:
        #When the app starts, jump to (instantiate) Main
        return Main(self._driver)

The Main module is the PageObject of the homepage, and its methods encapsulate important functions of the homepage. For example, goto_search_page in the following code encapsulates click search and jumps to the Search page:

from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.common.by import By

from test_appium.page.base_page import BasePage
from test_appium.page.profile import Profile
from test_appium.page.search import Search

class Main(BasePage):
    #After clicking the search button, enter the search page
    def goto_search_page(self):
        self.find(MobileBy.ID, "tv_search").click()
        #Enter the search page
        return Search(self._driver)

    def goto_stocks(self):

    def goto_trade(self):

    def goto_messages(self):

The Search module can search for a stock and obtain the price of the stock, such as the following figure:

The packaging code is as follows:

from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.remote.webdriver import WebDriver

class Search:
    _driver: WebDriver

    def __init__(self, driver):
        self._driver = driver
    #Enter what you want to search for
    def search(self, key: str):
        self._driver.find_element(MobileBy.ID, "search_input_text").send_keys(key)
        self._driver.find_element(MobileBy.ID, "name").click()
        return self
    #Get the stock price for judgment
    def get_price(self, key: str) -> float:
        return float(self._driver.find_element(MobileBy.ID, "current_price").text)

Finally, create a test for the above code and create a new test module test_search:

import pytest

from test_appium.page.app import App

class TestSearch:
    def setup(self):
        self.main = App().start().main()

    def test_search(self):
        assert self.main.goto_search_page().search("alibaba").get_price("BABA") > 200

The above is for your reference, please leave a message to discuss together.

Finally, I would like to thank everyone who has read my article carefully. Looking at the increase in fans and attention, there is always some courtesy. Although it is not a very valuable thing, if you can use it, you can take it directly!

Software testing interview documents

We must study to find a high-paying job. The following interview questions are from the latest interview materials from first-tier Internet companies such as Alibaba, Tencent, Byte, etc., and some Byte bosses have given authoritative answers. After finishing this set I believe everyone can find a satisfactory job based on the interview information.