使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 20--PO(POM) 设计模式和用例撰写

测试学习记录,仅供参考!

WEB自动化之掌握测试用例的撰写

常规(正常的写法):以设计功能测试的测试用例思路(如自顶向下等)来输写;

1、以开源电商商城系统测试项目 http://localhost:8088/ecshop/user.php 网站中的登录页面为例;

若是测试登录,需先定位到元素,输入内容(用户名、密码),点击立即登陆按钮,然后再断言结果;

注册测试登录账号;

2、在项目根目录 testcase 软件包下新建名称为 login 的目录文件,在 login 目录下新建名称为 test_login.py 的 Python 文件;

复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

class TestLogin:

    # 登录成功
    def test_login_success(self):
        driver = webdriver.Edge()
        # 打开浏览器网址
        driver.get('http://localhost:8088/ecshop/user.php')
        # 定位到登录页面的元素
        username = driver.find_element(By.NAME, 'username')
        password = driver.find_element(By.NAME, 'password')
        submit = driver.find_element(By.NAME, 'submit')
        # 输入用户名、密码,点击登录按钮
        username.send_keys('admin123')
        password.send_keys('123456')
        submit.click()
        # 断言结果
        success_ele = driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
        assert success_ele != ''
        sleep(2)

    # 登录失败
    def test_login_failed(self):
        pass

断言对象可以是页面标题、URL、登录成功的用户名称、登录成功返回信息等等;

继续编写登录失败场景的测试用例;

复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

class TestLogin:

    # 登录成功
    def test_login_success(self):
        driver = webdriver.Edge()
        # 打开浏览器网址
        driver.get('http://localhost:8088/ecshop/user.php')
        # 定位到登录页面的元素
        username = driver.find_element(By.NAME, 'username')
        password = driver.find_element(By.NAME, 'password')
        submit = driver.find_element(By.NAME, 'submit')
        # 输入用户名、密码,点击登录按钮
        username.send_keys('admin123')
        password.send_keys('123456')
        submit.click()
        # 断言结果
        success_ele = driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
        assert success_ele != ''
        sleep(2)

    # 登录失败
    def test_login_failed(self):
        driver = webdriver.Edge()
        # 打开浏览器网址
        driver.get('http://localhost:8088/ecshop/user.php')
        # 定位到登录页面的元素
        username = driver.find_element(By.NAME, 'username')
        password = driver.find_element(By.NAME, 'password')
        submit = driver.find_element(By.NAME, 'submit')
        # 输入用户名、密码,点击登录按钮
        username.send_keys('admin123')
        password.send_keys('123456789')
        submit.click()
        # 断言结果
        assert '系统提示' in driver.title
        sleep(2)

3、可以看到当前的测试用例每一个都得去写 一个初始化浏览器对象、定位元素、输入、断言,结合之前学习到的内容,做一些优化;把浏览器初始化对象放到前后置操作里面;

复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

class TestLogin:

    # 前置操作
    def setup(self):
        # 前面加上 self. 把它变成全局的,就可以在其他测试用例中调用这个对象了
        self.driver = webdriver.Edge()

    # 登录成功
    def test_login_success(self):

        # 打开浏览器网址
        self.driver.get('http://localhost:8088/ecshop/user.php')
        # 定位到登录页面的元素
        username = self.driver.find_element(By.NAME, 'username')
        password = self.driver.find_element(By.NAME, 'password')
        submit = self.driver.find_element(By.NAME, 'submit')
        # 输入用户名、密码,点击登录按钮
        username.send_keys('admin123')
        password.send_keys('123456')
        submit.click()
        # 断言结果
        success_ele = self.driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
        assert success_ele != ''
        sleep(2)

    # 登录失败
    def test_login_failed(self):

        # 打开浏览器网址
        self.driver.get('http://localhost:8088/ecshop/user.php')
        # 定位到登录页面的元素
        username = self.driver.find_element(By.NAME, 'username')
        password = self.driver.find_element(By.NAME, 'password')
        submit = self.driver.find_element(By.NAME, 'submit')
        # 输入用户名、密码,点击登录按钮
        username.send_keys('admin123')
        password.send_keys('123456789')
        submit.click()
        # 断言结果
        assert '系统提示' in self.driver.title
        sleep(2)

    # 后置操作
    def teardown(self):
        # 关闭浏览器
        self.driver.quit()

温馨提醒:

WARNING selenium.webdriver.common.selenium_manager:selenium_manager.py:127 Exception managing MicrosoftEdge: error sending request for url (https://msedgedriver.azureedge.net/LATEST_RELEASE_138_WINDOWS)

警告selenium.webdriver.comy.selenium_manager:selenium_manager.py:127管理MicrosoftEdge时发生异常:发送url请求时出错

pytest.PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.

testcase/login/test_login.py::TestLogin::test_login_failed is using nose-specific method: `setup(self)`

To remove this warning, rename it to `setup_method(self)`

See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose

\.venv\lib\site-packages\_pytest\python.py:887: PytestRemovedIn8Warning

控制台警告信息(网络查找问题原因)

表明在代码中使用了将在 Pytest 8.0 版本中移除的特性或写法。应该检查测试代码中使用了哪些即将被废弃的特性,并更新使用推荐的新特性。

自7.2版本起已弃用。在8.0版本中删除。现在已弃用对运行为nose编写的测试的支持。

nose只处于维护模式多年,维护插件并非易事,因为它会溢出代码库

解决方法:降低 pytest 版本,指定安装符合要求的(如需使用最新版本的,自行更改测试代码)

检查浏览器驱动版本(没有大版本更新,浏览器驱动问题基本可以排除)

4、 添加日志信息;

在 testcase 软件包下新建名称为 conftest.py 配置文件;与 @pytest.fixture 装饰器结合的全局前后置应用;

复制代码
import pytest
from util_tools.logs_util.recordlog import logs

@pytest.fixture(autouse=True)
def log_outputs():
    logs.info('------测试用例开始执行------')
    yield
    logs.info('------测试用例执行完毕------')

5、总结测试用例编写

每一个测试用例都这么写的话,后续维护起来会比较麻烦,这样写自动化测试的成本就远远大于做功能测试手动测试的成本了;若某一天,开发人员更改了某一个页面,得去测试用例里面去找相应的改动点修改;

这是最初没有采取任何措施任何设计模式的场景,后面引入 PO(POM) 模式,使用这种模式之后,可以把一些元素定位、操作等放到一个文件里面去,测试用例只需继承就可以去实现一系列相关操作的逻辑调用;这样后续维护起来会比较方便;

PO(POM)设计模式

在 web 自动化、app 自动化测试中一种最常用的设计模式,亦是用的比较多的;使用这种设计模块用于管理页面和测试用例方法;概念是比较抽象的,需要自行理解;

概念

Page Object Model(POM)是一种设计模式(页面对象模式),是为 Web UI 自动化测试创建对象库;通常在 UI 自动化测试中使用,特别是在 Selenium 自动化测试中,此种模式的目的是将页面的功能(页面元素和页面操作)和测试脚本分离,以提高自动化测试代码的可维护性和可重用性;

Page Object 模式将每个页面抽象为一个类,或者说是对每个页面进行抽象或建模的过程,是把一个具体的页面转化为编程语言当中的一个对象,页面特性转化成对象属性,页面操作转化为对象方法,该类包含页面的元素和操作;测试脚本通过调用 Page Object 类的方法来执行测试,在这种模式下,应用涉及的每一个页面应该定义为一个单独的类,类中应该包含此页面上的页面元素对象和处理这些元素对象所需要的方法等,将流程所关联的页面作为对象,将对象串联起来,形成一个个不同的流程;目前 PO(POM)设计模式仍是业内公认最佳的设计模式。

POM模式的主要概念:

页面类(Page Class)

每个被测试的页面都有一个相应的 Page class。这个类维护页面的所有元素和操作。元素通常被定义为类的变量,而操作通常被定义为类的方法。

行为和状态分离

Page Object 模式鼓励将页面的行为(例如点击按钮、填写表单)和状态(例如页面标题、元素可见性)封装到页面类中。这样,测试脚本可以专注于测试逻辑,而不必关心页面的具体实现。

可重用性

由于每个页面都有一个对应的 Page 类,这些类可以在不同的测试用例中被重复使用。如果页面发生变化,只需要更新相关的 Page 类,而不是每个测试用例。

易读性

通过将页面的结构和行为分离,测试脚本的可读性得到提高。测试脚本更加简洁,易于理解,因为不需要包含大量的页面操作和元素查找代码。

未完待续。。。

相关推荐
子不语1805 小时前
深度学习(一)——基础知识:Python语言/解释器/环境/编辑器
python·学习
许小禾上学记5 小时前
学习笔记 | 图论基础
笔记·学习·图论
爱学习的爬虫5 小时前
Python实现Jenkins实现自动化执行Job
python·自动化·jenkins
胡萝卜3.05 小时前
深入理解栈与队列:核心特性与实战应用
c++·学习·queue·stack·stack和queue的使用
一晌小贪欢6 小时前
Python爬虫第9课:验证码识别与自动化处理
爬虫·python·自动化·网络爬虫·python爬虫·python3
bin91536 小时前
AI工具赋能Python开发者:项目开发中的创意守护与效率革命
开发语言·人工智能·python·工具·ai工具
被放养的研究生6 小时前
Python常用的一些语句
开发语言·python
Run Freely9376 小时前
Python_封装案例
python
程序员爱钓鱼7 小时前
Python编程实战 · 基础入门篇 | 条件判断 if...else
后端·python