zoukankan      html  css  js  c++  java
  • Selenium Web自动化测试——基于unittest框架的PO设计模式

      引言

      前面一直在讲接口自动化测试框架与案例分享,很少讲Selenium这个Web自动化测试神器。它主要用来做UI自动化测试,大家都知道UI自动化测试成本相当高,一般的Web自动化测试我是一直不建议做的。

      虽然不推荐,但是这里有一个设计思想是不错的——PO设计模式。

      PO设计模式

      PO设计模式,英文名称:Page Object Model。PO设计模式是Selenium自动化测试中最佳的设计方式之一。相比传统设计中:页面定位元素→输入数据→操作元素→断言结果,会有以下问题:

      1、易用性差:杂乱无章的定位元素方法,例如:find_element;

      2、扩展性不好:用例孤立,无法扩展;

      3、复用性差:无公共方法,很难服用;

      4、可维护性差:一旦元素变化或测试步骤变化,需要维护大量代码和用例;

      针对上面一些弊端,做了一些优化:

      POM设计模式,将页面定位和业务操作分开,将元素定位和测试方法分离,从而提高代码的维护性。而传统的POM是元素定位和测试方法放在一起,如下图:

      

      这样做的优势:

      1、页面元素定位和业务操作方法分离,使得代码更加清晰,减少冗余代码;

      2、测试方法单独抽离,这样提高用例的可读性;

      3、针对ui变化频繁的项目和测试步骤的变化,提高了测试用例的维护性;

      一条测试用例可能需要多个步骤操作元素,将每一个步骤单独封装成一个方法,在执行测试用例时调用封装好的方法进行操作。PO模式可以把一个页面分为三个层级,对象库层、操作层、业务层。

      对象库层:封装定位元素的方法。
      操作层:封装对元素的操作。
      业务层:将一个或多个操作组合起来完成一个业务功能。

      PO设计模式核心组件

      画一个操作如下:

      

       首先抽象封装一个BasePage类,这个基类拥有Webdriver实例的属性,将页面分成一个个Page,每一个Page继承基类BasePage,可以通过driver来管理每一个Page中的元素,

      在Page中将定位元素的操作封装成一个一个方法。TestCase继承unittest里面的TestCase类,并且依赖Page类,进行测试步骤的执行工作。

      这样以来,页面元素一旦变化,只需要维护每一个Page中的方法,测试流程发生变化,只需要维护TestCase即可。

      核心组件:

      BasePage.py模块:

    class BasePage(object):
        def __init__(self,driver):
            self.driver = driver
    
        pass
    

      Page页面模块:

    from SeleniumProject.PO.BasePage import BasePage
    class LoginBase(BasePage):
        # 定位元素,括号中是通过find_element来获取元素的属性
        uname = ()
        pwd = ()
    
        def set_uname(self,uname):
            name =self.driver.find_element(*LoginBase.uname)
            name.send_keys("用户名")
        def set_pwd(self,pwd):
            password = self.driver.find_element(*LoginBase.pwd)
            password.send_keys("密码")
    
        pass
    

      TestCase用例模块:

    from unittest import TestCase
    import unittest
    from selenium import webdriver
    class Test_Login(TestCase):
        def setUp(self):
            self.driver = webdriver.Chrome()
            self.driver.get("https://cn.bing.com/")
    
        # 测试步骤
        def test_Login(self):
            self.driver.get(self.base_url)
            pass
    
        def tearDown(self):
            self.driver.quit()
    
    if __name__ == "__main__":
        unittest.main()
    

      

      PO模式简单实例

      现在根据PO设计模式思想,简单实现一个需求:

      打开浏览器,输入url:https://www.baidu.com,在百度搜索文本框内输入关键字:selenium,然后单击:百度一下,进行搜索。

      根据需求,设计步骤如下:

      BasePage:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
    # @Time    : 2020/11/22 0022 16:07
    # @Author  : liudinglong
    # @File    : basepage.py
    # @Description: 
    # @Question: 
    '''
    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    
    class BasePage(object):
        def __init__(self,driver,url):
            """
    
            @param driver:
            @param base_url:
            """
            self.dr = driver
            self.base_url =  url
    
        # 定义私有方法,类对象和子类可以访问
        def _open(self,url):
            self.dr.get(url)
            self.dr.maximize_window()
    
        # 定义open方法,调用_open方法
        def open(self):
            self._open(self.base_url)
    
        def find_emelemt(self,*loc):
            try:
                WebDriverWait(self.dr,10).until(EC.visibility_of_all_elements_located(loc))
                return self.dr.find_element(*loc)
            except:
                print("页面中没有%s元素"%(self.loc))
    
        # 定义script()方法,用于执行JS脚本,比方上上传文件啥的
        def script(self, src):
            self.dr.excute_script(src)
    
            # 定义页面跳转方法,比方说有的页面有frame嵌套
    
        def switch_frame(self, loc):
            return self.dr.switch_to_frame(loc)
    
            # 重新定义send_keys()方法,为了保证搜索按钮是否存在,还有有的输入框中默认有值,要清空
    
        def send_keys(self, loc, value, clear_first=True, click_first=True):
            try:
                # getattr方法相当于实现了self.loc
                loc = getattr(self, "_%s" % loc)
                # 是否存在搜索按钮
                if click_first:
                    self.find_emelemt(*loc).click()
                # 清空搜索框中的值,并输入需要搜索的值
                if clear_first:
                    self.find_emelemt(*loc).clear()
                    self.find_emelemt(*loc).send_keys(value)
    
            except:
                print("页面上未找到%s元素" % (self.loc))
    

      SearchPage:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
    # @Time    : 2020/11/22 0022 18:38
    # @Author  : liudinglong
    # @File    : SearchPage.py
    # @Description: 
    # @Question: 
    '''
    
    from selenium.webdriver.common.by import By
    from Common.basepage import  BasePage
    
    class SearchPage(BasePage):
        # 定位元素
        search_loc = (By.ID,"kw") #搜索框
        btn_loc = (By.ID,"su")    #搜索按钮
    
        # 重写父类的open()方法
        def open(self):
            self._open(self.base_url)
    
        def search_content(self,content):
            # 调用父类的find_emelemt,然后将本类的参数传入
            content1 =  self.find_emelemt(*self.search_loc)
            content1.send_keys(content)
    
        def btn_click(self):
            btn1 = self.find_emelemt(*self.btn_loc)
            btn1.click()
    

      TestCase:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    '''
    # @Time    : 2020/11/22 0022 18:40
    # @Author  : liudinglong
    # @File    : test_001.py
    # @Description: 
    # @Question: 
    '''
    
    from unittest import TestCase
    import unittest
    from selenium import webdriver
    from time import sleep
    from Page.searchpage import SearchPage
    class CaseRun(TestCase):
        def setUp(self):
            self.driver = webdriver.Chrome()
            self.url = "https://www.baidu.com"
            sleep(3)
            self.content = "selenium"
        # 测试步骤
        def test_search(self):
            bing_page = SearchPage(self.driver,self.url)
            bing_page.open()
            bing_page.search_content(self.content)
            try:
                bing_page.btn_click()
                sleep(3)
                print("查询成功")
            except Exception as Error:
                print(Error)
    
        def tearDown(self):
            self.driver.quit()
    
    if __name__ == "__main__":
        unittest.main()
    

      三个核心组件完成,项目结构如下:

      

       运行测试,生成报告如下:

    C:UsersAdministratorDesktopDemo_PO
    C:UsersAdministratorDesktopDemo_POReport
    .
    Time Elapsed: 0:00:13.370322
    
    Process finished with exit code 0

      总结

      这个Demo很简单,主要意图是帮助理解PO设计模式的思想,如果需要代码,可以加入QQ群:696400122 ,我们这里主要是进行自动化测试和测试开发学习与沟通交流,如果其他意图请绕行~

  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/liudinglong/p/14021596.html
Copyright © 2011-2022 走看看