Regarding UI automation testing, Tencent's big coffee said let you read this article before moving

As the basic skills of testers, UI automation testing has the characteristics of low ROI (input-output ratio), high maintenance cost, and poor stability. In the face of these problems, this article attempts to find solutions, hoping to be useful to everyone.

This article first lists the common problems encountered in the UI automation process, and then solves these problems one by one.

One, the problem of the century of UI automation

1. Low ROI (input-output ratio)

    Students who have done UI automation will definitely encounter this problem. The test cases written hard, not a few days after running, after the new requirements, the development changes the page, the original positioning control fails, and N tests The use case does not work. After each use case is changed, the UI has changed again, and it has to be changed again.                                        

2. High maintenance costs

   The faster the automated test script is constructed, the greater the maintenance cost. Some tests create test cases by recording return visits. Quickly construct hundreds of test cases. Maintaining test case compilation becomes a heavy task. For example, a slight change in a UI node may cause the automation tool to fail to recognize the UI control. Then all test cases that use this control need to be updated. Find and replace and ensure that there is no replacement error. A lot of work, not to mention that the general recorded scripts are not easy to understand manually. For another example, after running a test case, it takes a lot of time to troubleshoot errors. Errors include script errors, functional changes, and bugs. It takes a lot of manpower to investigate and solve one by one.

3. Poor stability

A certain test case works when it is debugged locally, but it fails when it is executed in batches.

A certain use case ran through last time, but it failed again this time. . .

There is clearly this element on the web interface, why can't it be found?

Investigate the reasons for these problems, but there are several reasons:

(1) Sleep is used in the code, but the page loading time is different under different network environments. When batch execution, the loading time is relatively long, sleep has ended, and the next sentence is run before the loading is successful. Caused the use case to fail.

(2) Use image recognition to locate buttons and other spaces. Different machine resolutions are different, and button controls cannot be recognized.

        In view of these difficulties, before starting UI automation, two issues need to be considered clearly: one is when to perform UI automation testing, and the other is how to do automation testing.

Second, the prerequisites for UI automation testing

1. UI tends to be stable

        Through the previous analysis of the maintenance cost of UI automation, it can be seen that the maintenance workload has a great relationship with whether the UI changes frequently. Before getting involved in UI automation, testers need to determine whether UI functions and processes are stable. If the UI function and process are stable, start UI automation. For a system, there is no need to wait for the entire system to be stable before intervening. After evaluating the stability of a certain independent function, the UI can be automated to test this function, and the framework and test cases can be optimized during the operation. Then wait for the other UI to stabilize, and the previous experience can be used in subsequent functions.

Of course, intervening in UI automation does not mean that all functions are realized by automation. The follow-up will be reduced to how to design automated test cases.

2. Lots of UI repeated operations

   If the UI function is stable, but the number of tests for this UI is small, the ROI of UI automation testing will be very low. For example, it takes 1 hour for a certain function to be manually specified, and 8 hours for UI automation (writing automation use cases, maintenance for each run), and this automation is only performed 5 times. It is equivalent to the time invested in automation is 3 hours longer than the time invested in manual testing. Therefore, UIs that require repeated operations are more suitable for UI automation testing. UI automation testing can release testers from heavy functional testing and perform more meaningful work.

  How to evaluate whether the UI is suitable for automated testing? You can evaluate the ROI of automated testing before performing automated testing to ensure that the ROI is relatively high, so that it is more suitable for UI automated testing.

Three, how to conduct UI automation testing

1. Design of test cases

       Before conducting UI automation testing, we must first clarify what is the purpose of UI automation testing? If it is to verify the color and arrangement of each control on the interface. Then the more such automation use cases, the more unstable, because the control is affected by the resolution and size of the test machine. If it runs successfully on one machine, it may fail on another machine. Once successful, it may fail next time. So we have to make it clear that UI automation testing is not to find more bugs, but to ensure the quality of the product. For example, if we log in to QQ on a web page, if we check the layout and color of the login button, it is actually unnecessary. We only need to log in to QQ through the UI operation and the login is successful, indicating that the login function is normal. If development affects the login function in the process of changing the code, resulting in login failure, we can find the problem through this automated use case.

 Therefore, the test cases of the main process can be realized as automated use cases. That is, the smoke test case can be realized.

2. Separation of controls and use cases

First look at a login test case:

'''登录
'''
browser = webdriver.Chrome()
# 打开页面
browser.get("http://bugui.test.tui.qq.com/")
# 点击登录按钮
login_button = browser.find_element_by_xpath("//a[@class='login_btn fR']")
login_button.click()
# 账号密码登录按钮
browser.find_element_by_id('switcher_plogin').click()
# 输入账号
browser.find_element_by_id('u').send_keys(123456)
# 输入密码
browser.find_element_by_id('p').send_keys(123456)
# 登录
browser.find_element_by_class_name('login_button').click()

 In the test case, directly specify the id or class_name of the control to find the element and then perform the operation. There are three problems:

(1) If the id or class_name of an element is modified by the development, then the related test cases need to be modified, and the maintenance cost is too high

(2) Operate the control through class_name or id, which makes the code readability too bad. If there is no comment, others will not understand what this long code is doing.

(3) Login is only a prerequisite for all use cases. For example, the prerequisite for creating an advertisement is to log in first. If all logins have such a login code, the use case will be very long

How to solve it? Look at the following code again to abstract the space in the page:

''' 登录页面抽象类 '''
class LoginPage(object):
    ''' 登录页面 '''
    def __init__(self,driver):
        '''返回一个控件字典 '''
        if driver is None:
            raise WebDriverException("浏览器不能为空")
        self.driver = driver
        self.Controls={}.fromkeys(('登录按钮','账号密码登录按钮','QQ号输入框','密码输入框', '登录智汇推'))
        
        # 控件抽象
        self.Controls['登录按钮']=self.driver.find_element_by_xpath("//a[@class='login_btn fR']")
        self.Controls['账号密码登录按钮'] = self.driver.find_element_by_id('switcher_plogin')
        self.Controls['QQ号输入框'] = self.driver.find_element_by_id('u')
        self.Controls['密码输入框'] = self.driver.find_element_by_id('p')
        self.Controls['登录智汇推'] = self.driver.find_element_by_class_name('login_button')

 Encapsulate the login operation, instantiate LoginPage, and operate the controls of the login page:

def login_tui(tui_url, qq_num, qq_psw):
    '''登录智汇推的公共函数'''
    browser = webdriver.Chrome()
    browser.get(tui_url)
    login_page = LoginPage(browser)
    login_page.Controls['登录按钮'].click()
    login_page.Controls['账号密码登录按钮'].click()
    login_page.set_qq_num(qq_num)
    login_page.set_qq_psw(qq_psw)
    login_page.Controls['登录智汇推'].click()
    return browser

 When any id is adjusted, just modify the content of LoginPage, which reduces the maintenance cost. Each control is named by Chinese name, which enhances the readability of test cases. At the same time, the method of encapsulating functions, as long as the method is called in the use case, makes the use case more concise and easy to maintain.

3. Use sleep as little as possible

 Most web applications now use Ajax technology. When a page is loaded into the browser, the elements in the page can be loaded at different points in time. This makes it difficult to locate the element. If the element is no longer in the page, an ElementNotVisibleException will be thrown. Some people use the sleep method to wait for the page to load successfully, such as sleep(5). If the network is unstable and the page is loaded for 10 seconds, then this sleep is useless. Then you can say that I can sleep (30) before proceeding to the next step, but in this case, the execution time of the use case becomes a lot longer, and there is no advantage to manual execution.

There are two ways to reduce sleep:

(1)WebDriverWait

 Using selenium for web automation testing can use the WebDriverWait method, which can be used by google:

# 当页面元素可见后,表示页面加载成功
self.flag_frame = 'ui_ptlogin'
locator = (By.NAME, self.flag_frame)
WebDriverWait(self.driver, 20).until(EC.frame_to_be_available_and_switch_to_it(locator))

For non-web UI automation testing, you can design some methods like waitForInvisiable yourself to wait for the control to load successfully.

(2) TimeOut method adds retry logic

When selenium executes the drop-down box selection, there is a certain probability that it will fail. Adding retry logic here will improve the stability of the use case. Give an example of retry logic:

class Timeout(object):
    '''Timeout类,实现超时重试逻辑'''
    
    def __init__(self, timeout = 10, interval = 0.5):
        ''' @param timeout:超时描述,默认是10 @param interval:重试时间间隔秒数,默认是0.5 '''
        
        self.timeout = float(timeout)
        self.interval = float(interval)
    
    def retry(self, func, args, exceptions=(), resultmatcher=None, message=""):
        """多次尝试调用函数,成功则并返回调用结果,超时则抛出异常。 :param func: 尝试调用的函数 :type args: dict或tuple :param args: func函数的参数 :type exceptions: tuple类型,tuple元素是异常类定义,如QPathError, 而不是异常实例,如QPathError() :param exceptions: 调用func时抛出这些异常,则重试。 如果是空列表(),则不捕获异常。 :type resultmatcher: 函数指针类型 :param resultmatcher: 函数指针,用于验证第1个参数func的返回值。 默认值为None,表示不验证func的返回值,直接返回。 其函数原型为: def result_match(ret): # 参数ret为func的返回值 pass 当result_match返回True时,直接返回,否则继续retry。 :return: 返回成功调用func的结果 """  
        start = time.time()
        waited = 0.0
        try_count = 0
        while True:
            try:
                try_count += 1
                if dict == type(args):
                    ret = func(**args)
                elif tuple == type(args):
                    ret = func(*args)
                else:
                    raise Exception("args type %s is not a dict or tuple" % type(args))
                
                if resultmatcher == None or resultmatcher(ret) == True:
                    print "%s Timeout尝试次数: " % message, try_count
                    TestLog.log_info("%s Timeout尝试次数: %s" % (message, str(try_count)))
                    return ret
            except exceptions:
                pass
            waited = time.time() - start
            if waited < self.timeout:
                time.sleep(min(self.interval, self.timeout-waited))
            elif try_count == 1:
                continue
            else:
                raise Exception("在%d秒里尝试了%d次" % (self.timeout, try_count))
        print try_count

 

4. Coordinates and image recognition are not used in the script

Selenium provides many methods to find the control, try to find the control by id or class_name. However, there is a situation where the id of the dynamic layout conditions are the same and cannot be distinguished. My experience is to search through the text method:

driver.find_element_by_xpath("//*[text()='%s']" % string)

5. Ensure the independence of use cases

Try to ensure that a test case only does one thing, and there is no correlation between the use case and the use case, which can improve the stability of the use case

6. Try not to use UI operations where you can not use UI

For example, the purpose of the use case is to check the display function of the advertisement information. It is necessary to create a new advertisement. Creating an advertisement through the interface is particularly complicated. You can create an advertisement through the API and check it on the interface. This will simplify the complexity.

The following is my collection and sorting in recent years, the whole is organized around [software testing], the main content includes: python automation test exclusive video, Python automation details, a full set of interview questions and other knowledge content.
Insert picture description here
For software testing friends, it should be the most comprehensive and complete interview preparation warehouse. In order to better organize each module, I also refer to many high-quality blog posts and projects on the Internet, and strive not to miss every knowledge point. Friends relied on these contents to review and got offers from big factories such as BATJ. This warehouse has also helped many learners of software testing, and I hope to help you too.

Follow the WeChat public account [Programmer Erhei] to receive Python automated testing super hard core resources

Guess you like

Origin blog.csdn.net/m0_52650621/article/details/112895250