局外人1

V1

2022/07/26阅读:31主题:默认主题

自动化测试 PO设计模型

POM(Page Object Model) 即是页面对象模型

设计模式在开发中比不少见,我们都知道后端开发有MTV/MVC等设计模式、那么我们的PO设计模式也可以当做为自动化测试开发的一种开发模式,顾名思义Page 就是页面 Object 就是对象,编程界里万物皆对象那么我们在做自动化测试的时候也能将其对每个页面封装成一个又一个的对象进行管理

其作用是为了能把项目的每个页面的元素和测试的业务逻辑、数据处理进行分离,将其每一个页面都封装成一个页面类,每一个页面类都需要继承至一个叫 PageBase类作为基类,该基类仅封装一些对于每个页面都需要使用到的selenium API 如启动浏览器打开url界面等这些常用的方法,如果你觉得这些还不足以满足你的要求其实可以将selenium/appium二次封装也放在这个类中。

PO设计模型是目前业界做UI自动化测试作为主流且常见的一种设计模式了,几乎只要有做自动化就必要使用该设计模型,因为现阶段没有比PO设计模式更好的设计模式了。

PO是什么?

1、页面对象模型(PO)是一种设计模式,用来管理维护一组web元素的对象库。

2、在PO下,应用程序的每一个页面都有一个对应的page class

3、每一个page class维护着该web页的元素集和操作这些元素的方法。

4、page class中的方法命名最好根据对应的业务场景进行命名。

Page Object模式具有以下几个优点

1、PO提供了一种业务流程与页面元素操作分离的模式,测试代码变得更易读、 灵活、 可维护。

2、页面对象与用例分离,使得我们更好的复用对象。

3、可复用的页面方法代码会变得更加优化。

4、更加有效的命名方式使得我们更加清晰的知道方法所操作的UI元素。

5、降低了自动化测试的维护成本、前端页面变化多端在维护时仅对页面元素进行修改即可。

分层架构

PO模式最核心的思想是分层,实现松耦合!实现脚本重复使用,实现脚本易维护性! 分层机制,让不同层去做不同类型的事情,让代码结构清晰,增加复用性。

架构图

Page Object Model 实现思路

step 1:首先定义一个PageBaseClass将该类里进行封装些基础方法 如:启动浏览器操作、打开URL操作,selenium/appium API二次封装等。 Page Object models PageBase 用于启动各个page的前置条件 如启动浏览器 打开URL

class PageBase:
    
    def __init__(self,driver,timeout=3):
        
        self.driver = driver
        #获取webdriver实例
        
        self.url = AUTO_PROJECT["front"]
        #默认url 为项目登录界面
        self.driver.implicitly_wait(timeout)
        #全局元素定位等待

        def open(self,url=None):
            if url:
                self.url = url
  
            return self.driver.get(self.url)
      ......

step 2:将每一个定义的Page Class 都继承至 PageBase Class、并进行对页面进行封装、每个页面应为一个类、每个页面内的操作元素仅封装定位一次,且不需要每个元素都进行封装、用到了元素封装即可、封装完后的每一个元素都需要将页面对象的实例return出去(如果是操作与元素分离)。

from common.Element import PageBase
from selenium.webdriver.common.by import By
from selenium import  webdriver

class MallLoginPage(PageBase):
    @property
    def form_login(self):
        """电话号码"""
        return self.webWait(
            by=(By.XPATH,'//*[@id="app"]/div/div/form/div[1]/div/div[2]/input')
        )
    @property
    def form_password(self):
        """密码"""
        return self.webWait(
            by=(By.XPATH,'//*[@id="app"]/div/div/form/div[2]/div/div/input')
        )
    @property
    def button_sign(self):
        """登录按钮"""
        return self.webWait(
            by=(By.XPATH,'//*[@id="app"]/div/div/form/div[3]/div/button')
        )

    @property
    def login_text(self):
        """断言文本获取登录后的"""
        return self.webWait(
            by=(By.XPATH,'//*[@id="app"]/div/div/div[1]/div/span/span[2]')
        )

step 3:再进行对封装好的每一个元素(如果是的关键字就是每一个方法对应一个元素定位不包含操作)进行拼装成一个完整的操作流程,数据需要分离就需要定义参数,用于在unittest框架中进行调用时传入不要写死。

def mall_login(self,phone,password):
    self.form_login.send_keys(phone)
    self.form_password.send_keys(password)
    self.button_sign.click()
    

step 4:使用单元测试框架进行管理测试用例及处理业务逻辑

class Login(unittest.TestCase):
    """登录用例"""

    def setUp(self):
        self.driver = webdriver.Chrome()
        self.LoginPage = LoginElement(driver=self.driver)

    def test_login_normally(self):
        """正常登录"""
        self.MallLoginPage.mall_login(
            username=61234567,
            password="gfl13453001",
            des="正常登录"
        )
        text = self.LoginPage.login_text.text
        self.assertEqual(text,'登入成功',msg="登录的用户名与预期不一致")



    def test_login_error_password(self):
        """错误的密码登录"""
        self.MallLoginPage.mall_login(
            username=61234567,
            password="gfl1345300",
            des="错误的密码登录"
        )
        text = self.LoginPage.login_text_error.text
        self.assertEqual(text,'電話號碼或密碼錯誤',msg="電話號碼或密碼錯誤")


    def tearDown(self):
        self.driver.quit()



if __name__ == '__main__':
    unittest.main()

以上就是大致的一个三层实现的一个思路、通过上面案例可以更具自己企业项目来进行做对应的修改只要遵循了PO设计模型就可以了。

使用了PO设计模式明显的可以看出测试用例变得简洁,而且看到也非常明了易懂,且也容易维护。

分类:

后端

标签:

软件测试

作者介绍

局外人1
V1