搭建Web自动化测试框架

测试框架的设计有两种思路,一种是自底向上,从脚本逐步演变完善成框架,这种适合新手了解框架的演变过程。另一种则是自顶向下,直接设计框架结构和选取各种问题的解决方案,这种适合有较多框架事件经验的人。本章和下一张分别从两种设计思路来介绍框架的搭建过程。

从脚本到用例

相比于一堆测试脚本,使用规范化的测试用例格式会方便我们灵活的执行和管理用例。一个完整的自动化测试用例应包含:

  • 测试准备(setup):测试准备步骤、用例辅助方法或工具,可以共用;
  • 测试步骤(test steps):核心测试步骤;
  • 断言(assertions):期望结果于实际结果的比对,用例可以报告不止一个断言;
  • 测试清理(teardown):对执行测试造成的影响进行清理和还原,以免影响后续执行,可以共用。

编写测试函数

将测试脚本转化为Pytest测试用例的方法非常简单,只要将测试过程编写为test开头的测试函数即可。
有时候我们为了快速实现一个功能,会直接把代码按步骤写到模块里,如下例:

代码test_baidu_search_v0.9.py内容

from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
driver.find_element_by_id('kw').send_keys('博客园 韩志超')
driver.find_element_by_id('su').click()
sleep(1)
if '韩志超' in driver.title:
    print('通过')
else:
    print('失败')
driver.quit()

然后我们开启第一步优化,首先,可以把步骤写到一个函数里,这样方便在脚步中写多个用例,另外,我们可以按照Pytest测试框架用例到写法,写成标准的用例。期望结果的判断我们使用标准的assert断言语句,修改后如下:

代码test_baidu_search_v1.0.py内容

from selenium import webdriver
from time import sleep

def test_baidu_search_01():
    driver = webdriver.Chrome()
    driver.get("https://www.baidu.com")
    driver.find_element_by_id('kw').send_keys('博客园 韩志超')
    driver.find_element_by_id('su').click()
    sleep(1)
    assert '韩志超' in driver.title, '标题不包含韩志超'  # 自定义失败消息
    driver.quit()

不同于v0.9版Python脚本的运行方法(命令行使用python <脚步路径>),Pytest用例脚本使用pytest <脚本路径>或python -m pytest <脚本路径>来执行。
我们也可以在Pytest用例脚本下面加上以下语句,

if __name__ == '__main__':
    pytest.main([__file__])

这样便可以像Python脚本一样直接运行。其中__file__指当前脚本,也可以添加其他运行参数,如-qs等。

使用断言

测试用例中必须包含期望结果来验证执行的通过与否。不同于“调试”,需要有人值守来人工判断没个执行过程是否通过,自动化“测试”往往需要批量运行,并自动判断用例是否通过。断言即是执行过程中的实际结果与期望结果的自动对比。
Pytest中使用标准的assert语句来进行断言。assert断言语句在用例执行失败时(和期望结果不一致)会抛出AssertionError异常,测试框架会自动捕获该异常,并将用例标记为执行失败状态,并且不会因为异常导致执行中断而影响其他用例的执行。

注:在用例中也可以使用if判断配合pytest.fail()或者手动抛出AsserionError异常来将用例设置为失败状态,示例如下:

    if '韩志超' not in driver.title:
        # rasie AssersionError('标题不包含韩志超')
        pytest.fail('标题不包含韩志超')

Web UI自动化测试过程中常用的断言策略有以下几种:

  • 流程成功执行视为通过:按确定的元素操作步骤,可以正常完成整个流程视为通过;
  • 通过标题断言:通过当前网页标题driver.title来判断处于某一页面上;
  • 通过URL断言:通过当前URL,driver.current_url来判断处于某一页面上;
  • 通过页面源码断言:通过网页源代码driver.page_source中包含特定信息来判断处于某一页面上;
  • 通过存在特定元素断言:通过存在某个特定元素来判断处于某一页面上。

通过元素判断是否在某一页面上的示例如下:

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

def test_open_baidu():
    driver = webdriver.Chrome()
    driver.get("https://www.baidu.com")
    try:
        driver.find_element_by_id('kw')  # 尝试定位搜索框
    except NoSuchElementException:
        pytest.fail('不存在搜索框')

在框架中,可以将常用的断言方法进行封装以方便使用。

分离测试准备及清理方法

在测试用例中,我们要尽可能的分离核心测试步骤,将可以共用的测试准备及测试清理步骤单独提取出来,以方便复用。
在上例中,我们核心的测试步骤是从打开百度网站到断言网页标题,而启动浏览器和关闭浏览器可以视为测试准备和测试清理方法。
测试准备和测试清理方法我们可以使用Pytest中的setup_function()及teardown_function()方法,也可以使用自定义的Fixture方法来吧两个方法集中的一个函数中,如下例:

代码test_baidu_search_v3.py内容

from time import sleep

from selenium import webdriver
import pytest

def setup_function():
    global driver
    driver = webdriver.Chrome()

def teardown_function():
    driver.quit()

def test_baidu_search_01(driver):
    driver.get("https://www.baidu.com")
    driver.find_element_by_id('kw').send_keys('博客园 韩志超')
    driver.find_element_by_id('su').click()
    sleep(1)
    assert '韩志超' in driver.title

if __name__ == '__main__':
    pytest.main([__file__])

使用自定义Fixture方法

代码test_baidu_search_v4.py内容

from time import sleep

from selenium import webdriver
import pytest

@pytest.fixture
def driver():
    dr = webdriver.Chrome()
    yield dr
    dr.quit()

def test_baidu_search_01(driver):
    driver.get("https://www.baidu.com")
    driver.find_element_by_id('kw').send_keys('博客园 韩志超')
    driver.find_element_by_id('su').click()
    sleep(1)
    assert '韩志超' in driver.title

if __name__ == '__main__':
    # --html需要pip install pytest-html
    pytest.main([__file__, '--html=report.html','--self-contained-html'])

上例中我们自定义了一个名为driver的Fixture方法。yield上面对的所有语句属于测试准,这里创建了一个浏览器驱动对象dr。yield语句将dr对象交给用例执行,并等待用例执行完毕,再执行下面的测试清理语句,退出浏览器。
用例中使用Fixture函数名driver作为参数来注入测试准备和测试清理方法,用例中使用的driver即Fixture函数yield返回的dr,浏览器驱动对象。

使用Pytest-selenium插件

Pytest框架的优点之一是,拥有很多功能丰富的插件。使用这些插件可以省略我们自己编写Fixture方法的过程,直接安装使用。
上例中我们自己编写了一个名为driver的fixture方法,我们也可以直接使用Pytest-Selenium插件,该插件提供了一个全局的driver(或selenium)Fixture方法,可以直接使用,并且支持切换使用的浏览器。安装Pytest-Selenium插件,并修改代码如下:

代码test_baidu_search_v5.py内容

from time import sleep

from selenium import webdriver
import pytest

def test_baidu_search_01(driver):
    driver.get("https://www.baidu.com")
    driver.find_element_by_id('kw').send_keys('博客园 韩志超')
    driver.find_element_by_id('su').click()
    sleep(1)
    assert '韩志超' in driver.title

if __name__ == '__main__':
    # --html需要pip install pytest-html
    # --driver 需要pip install pytest-selenium
    pytest.main([__file__, '--driver=chrome', '--html=report.html','--self-contained-html'])

pytest-selenium还支持配置浏览器选项及配合pytest-html失败自动截图等功能,详细可以参考其官方使用文档https://pytest-selenium.readthedocs.io/en/latest/。

注:pytest-selenium默认会拦截所有接口请求,可以在pytest.ini中配置sensitive_url = ''来设置无敏感url。

生成测试报告

使用Pytest框架生成测试报告最常用的插件有pytest-html和allure-pytest两种,前者简单,可以生成单文件测试报告。后者华丽,功能强大,使用较为复杂。本章我们使用pytest-html来生成报告,allure-pytest的具体使用下章讲解。
pytest-html的使用方式非常简单,安装pytest-html并使用--html来生成报告即可:
if name == 'main':
# --html需要pip install pytest-html
pytest.main([file, '--html=report.html','--self-contained-html'])

注:如果想自己生成HTML测试报告,可以在conftest.py文件中通过pytest_terminal_summary钩子方法terminalreporter参数对象的stats属性结合三方库Jinjia2来自定义生成报告。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值