web自动化测试中的PO模式(一)

1、PO模式的思想

  1. 原理:
    1. 将页面的元素定位和元素行为封装成一个page类
    2. 类的属性:元素的定位
    3. 类的行为:元素的操作 
  2. 页面对象和测试用例分离
  3. 测试用例:
    1. 调用所需要页面对象中的行为,组成测试用例
    2. 测试用例中,只需要含有页面函数的调用和断言,不应该出现元素定位等其他的操作,如果写测试用例中出现需要其他的额外的操作,可以想办法封装到页面对象或者元素定位中
  4. 好处:
    1. 当某个页面的元素发生变化,只需要修改该页面对象中的代码即可,测试用例不需要修改
    2. 提高代码的重用率,结构清晰,维护代码容易
    3. 测试用例发生变化是,不需要或者只需要修改少数页面对象代码即可

2、使用unittest框架实现PO模式

  1. 新建一个包,命名为PageObjects,包中用来封装各个页面的功能
    1. 页面对象封装的类中,函数用来实现页面的功能,在类的初始化函数中,使用传参(driver)的方式完成,页面只需要实现对应功能即可,具体传入什么样的测试,在测试用例的前置条件中实现,可以提高函数的重用率
      1. 页面对象封装函数
         1 from selenium.webdriver.support import expected_conditions as EC
         2 from selenium.webdriver.support.wait import WebDriverWait
         3 from selenium.webdriver.common.by import By
         4 class LoginPage:
         5     def __init__(self,driver):
         6         self.driver=driver
         7 
         8     def login(self,username,pwd,remember_user=True):
         9         # 等待定位元素出现
        10         WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.XPATH,"//input[@name='phone']")))
        11         # 输入用户名
        12         self.driver.find_element_by_xpath("//input[@name='phone']").send_keys(username)
        13         # 输入密码
        14         self.driver.find_element_by_xpath("//input[@name='password']").send_keys(pwd)
        15         # 定位记住手机号元素
        16         remember_ele=self.driver.find_element_by_xpath("//input[@name='remember_me']")
        17         # 判断时候记住手机号
        18         if remember_user==True:
        19             remember_ele.checked=True
        20         else:
        21             remember_ele.checked=False
        22         # 点击登录
        23         self.driver.find_element_by_xpath("//button[text()='登录']").click()
      2. 测试用例调用页面对象函数,代码如下

        1     def test_login_success(self):
        2         # 2、步骤
        3         # 实例化LoginPage类
        4         lg=LoginPage(self.driver)
        5         # 调用login方法
        6         lg.login("登录账号","登录密码")
        7         # 3、断言
        8         self.assertTrue(IndexPage(self.driver).isExist_logout_ele())
      3. Index_page页面封装函数代码
        from selenium.webdriver.support import expected_conditions as EC
        from selenium.webdriver.support.wait import WebDriverWait
        from selenium.webdriver.common.by import By
        class IndexPage:
            def __init__(self,driver):
                self.driver=driver
        
            def isExist_logout_ele(self):
                try:
                    WebDriverWait(self.driver,10).until(EC.visibility_of_element_located((By.XPATH,"//a[text()='退出']")))
                    return True
                except:
                    return False
      4. 测试用例的前置条件代码
        import unittest
        from selenium import webdriver
        from PageObjects.login_page import LoginPage
        from PageObjects.index_page import IndexPage
        class TestLogin(unittest.TestCase):
        
            def setUp(self):
                # 1、前置条件
                url="http://ip:host/Index/login.html"
                self.driver=webdriver.Chrome()
                self.driver.maximize_window()
                self.driver.get(url)
      5. 运行测试用例可以在测试用例最后面使用一下代码,然后运行该代码
        if __name__ == '__main__':
            unittest.main()
      6. 运行结果如下,表示运行成功  
  2. 新建一个包,命名为TestCases,包中用来写测试用例,测试用例中用到那个页面对象中的函数时,只需要调用页面对象中的函数就可以了
  3. 新建一个包,命名为TestDatas,用来写测试数据,将测试数据的类导入到测试用例模块中,进行使用,这样的话,测试数据便于管理,测试数据添加、修改、删除不用修改测试用例
    1. 在TestCases下面新建一个公用的数据管理.py文件Common_Datas.py和模块数据的.py文件login_datas.py,如下t图:

        

      #Common_Datas.py
      web_login_url="http://ip:port/Index/login.html"
      
      #login_datas.py
      #正常场景---测试数据
      success_data={"user":"18000123456","pwd":"123456"}
      
      # 异常用例--手机号格式不正确(大于11位,小于11位,为空,不在号码段)
      error_data=[
          {"user": "180001234561", "pwd": "123456","check":"请输入正确的手机号"},
          {"user": "1800012345", "pwd": "123456","check":"请输入正确的手机号"},
          {"user": "10684723485", "pwd": "123456","check":"请输入正确的手机号"},
          {"user": "", "pwd": "123456","check":"请输入手机号"},
          {"user": "18000123456", "pwd": "","check":"请输入密码"},
          {"user": "", "pwd": "","check":"请输入手机号"},
      ]
    2. 在测试用例模块使用数据管理模块中的数据
       1 import unittest
       2 from selenium import webdriver
       3 from PageObjects.login_page import LoginPage
       4 from PageObjects.index_page import IndexPage
       5 from TestDatas import Common_Datas as CD
       6 from TestDatas import login_datas as ld
       7 from ddt import ddt,data
       8 
       9 @ddt
      10 class TestLogin(unittest.TestCase):
      11     @classmethod
      12     def setUpClass(cls):
      13         # 1、前置条件
      14         cls.driver=webdriver.Chrome()
      15         cls.driver.maximize_window()
      16         cls.driver.get(CD.web_login_url)
      17         # 实例化LoginPage类
      18         cls.lg=LoginPage(cls.driver)
      19     @classmethod
      20     def tearDownClass(cls):
      21         cls.driver.quit()
      22 
      23     def tearDown(self):
      24         self.driver.refresh()
      25         pass
      26     # 正常用例--登录成功
      27     def test_login_1_success(self):
      28         # 2、步骤
      29 
      30         # 调用login方法
      31         self.lg.login(ld.success_data['user'],ld.success_data['pwd'])
      32         # 3、断言
      33         self.assertTrue(IndexPage(self.driver).isExist_logout_ele())
      34     # 异常用例--手机号码格式不正确(大于11位,小于11位,为空,不在号码段)  ddt
      35     @data(*ld.error_data)
      36     def test_login_0_user_wrongFormat(self,item):
      37         self.lg.login(item['user'],item['pwd'])
      38         self.assertEqual(self.lg.get_errorMsg_form_loginArea(),item['check'])

      备注:

      setUpClass(cls)函数和tearDownClass(cls)只在整个用例开始和结束时运行一次,必须使用@classmethod来修饰,如上面的异常测试用例有6条,在用例开始前和结束时只运行一次 
      setUp(self)函数和tearDown(self)在每个测试用例开始和结束时运行,如果使用这两个函数,上面的6条用例,每运行一个,就会运行一次这两个函数,总共运行6次
      tearDown(self)可以和setUpClass(cls)函数和tearDownClass(cls)函数结合使用,如上面的界面刷新self.driver.refresh()和页面关闭cls.driver.quit()
    3. 测试用例类型相同的测试数据可以设计在一起,使用ddt在测试用例运行时分别执行测试用例
    4. 使用unittest框架,运行测试用例,如下:
       1 import unittest
       2 from TestCases.test_login import TestLogin
       3 from HTMLTestRunnerCN import HTMLTestReportCN
       4 # 创建一个容器,用来存测试用例
       5 suite=unittest.TestSuite()
       6 # 加载测试用例的类的实例
       7 loader=unittest.TestLoader()
       8 # 将测试用例加载到suite容器中
       9 suite.addTest(loader.loadTestsFromTestCase(TestLogin))
      10 # 打开文件,用来写测试报告
      11 with open("test_result.html",'wb') as file:
      12 
      13     # runner=unittest.TextTestRunner(verbosity=1)
      14 
      15     runner=HTMLTestReportCN( stream=file, verbosity=2, title="web自动化测试", description="第一个web自动化测试", tester="wsk")
      16     # 运行测试用例
      17     runner.run(suite)
    5. 运行结果,如下图:

       在写测试用例时,如果使用unittest框架可以使用函数名来控制代码的执行顺序,如:

      ok test_login_0_user_wrongFormat_6 (TestCases.test_login.TestLogin)  --------------------  0  
      ok test_login_1_success (TestCases.test_login.TestLogin)------------------------------------------1    前面都一样,0比1小,先运行

  

猜你喜欢

转载自www.cnblogs.com/wsk1988/p/12713857.html