一文打通软件测试中pytest框架
介绍
pytest是单元测试框架,在软件测试中作用是管理测试用例, 执行测试用例, 生成测试报告。该框架能够组织多个用例去执行,方便实现参数化。
安装
windows黑窗口安装,考虑到默认下载地址是国外,加上镜像源,采用清华大学镜像源,命令:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pytest
安装完成后,可以使用下面命令查看是否成功,有弹出版本号即成功。
pytest --version
卸载:
pip uninstall pytest
pytest书写用例
步骤:
1.定义测试类(建议类名以 Test开头)
2.书写测试方法, 即真正的用例代码(建议方法名以 test 开头)
注意:测试用例的代码文件名不要使用中文, 遵循标识符的规则,文件名建议以 test 开头。
示例:
class TestCase:
def test_method1(self):
print('测试方法1') # 用打印模拟真正的测试代码
def test_method2(self):
print('测试方法2')
pytest执行用例
方法一:在终端中用命令
pytest -s 用例代码文件
-s的作用是输出显示代码中的print

方法二:使用配置文件运行(重点)
配置文件创建在代码的根目录中,名字一般写作 pytest.ini ,第一行必须是[pytest],有了配置文件后,之后终端中运行,都会调用配置文件。
[pytest]
# 选项
addopts = -s
# 文件所在目录
testpaths = scripts/
# 文件名
python_files = test*.py
# 测试类名
python_classes = Test*
# 测试方法名
python_functions = test*

断言
让程序代码自动判断预期结果和实际结果是否相符。如果相符,则断言成功,用例通过。如果不相符, 则断言失败,用例不通过,抛出异常。断言使用的是 assert 关键字,2种使用方法,如下:
assert 预期结果 == 实际结果 # 断言是否相等
assert 预期结果 in 实际结果 # 断言预期结果是否包含在实际结果中
加法案例练习
测试如下代码,写在tools.py里面:
def add(a, b):
return a + b
测试数据如下:
1,10,11 1,9,10
测试代码如下:
from tools import add
class TestAdd:
def test_method1(self):
print('1,10,11')
assert 11 == add(1,10)
def test_method2(self):
print('1,9,10')
assert 10 == add(1,9)

参数化
上面2个用例只是测试数据不同,其他都相同,这种情况可以使用参数化来优化代码。
步骤:
-
将用例中的数据变为参数书写
-
组织测试数据 ---> [(), (), ()]或者 [[], []], 内部的元组或者列表就是一组测试数据
-
使用装饰器完成参数化
例子:
测试代码:
import pytest
from tools import add
data = [(1,10,11),(1,9,10)]
class TestAdd:
@pytest.mark.parametrize('a,b,expect',data)
def test_method1(self,a,b,expect):
print(f'{a},{b},{expect}')
assert expect == add(a,b)

项目分目录处理
上面的代码中测试数据和测试用例混合在一起,不规范,应该分开,一分开的话就需要有读取测试数据的代码,这些都要进行规范化管理。
- pytest.ini 放在项目根目录下
- 测试数据单独一个目录data
- 读取测试数据一般放在common包中
- 读取数据时要用绝对路径,路径一般比较长,直接写在项目的配置文件config.py中
- 用例代码(脚本)一般script包中
项目分目录截图:

例子:
pytest.ini:
[pytest]
# 选项
addopts = -s
# 文件所在目录
testpaths = scripts/
# 文件名
python_files = test_004.py
# 测试类名
python_classes = Test*
# 测试方法名
python_functions = test*
config.py
import os
BASE_PATH = os.path.dirname(__file__) # 获取当前项目的路径
tools.py
def add(a, b):
return a + b
add.json:
[[1,10,11],[1,9,10]]
read_data.py:
import json
from config import BASE_PATH
def read_datas():
with open(BASE_PATH + '/data/add.json',encoding='utf-8') as f:
data = json.load(f)
return data
if __name__ == '__main__':
print(read_datas())
test_004.py:
import pytest
from common.read_data import read_datas
from tools import add
class TestAdd:
@pytest.mark.parametrize('a,b,expect',read_datas())
def test_method1(self,a,b,expect):
print(f'{a},{b},{expect}')
assert expect == add(a,b)

测试报告
步骤:
-
安装,黑窗口安装
pip install pytest-html -i https://pypi.douban.com/simple -
在 pytest 配置文件中添加配置选项
addopts = -s --html=report/login_report.html --self-contained-html
-
项目添加报告目录

-
结果中有提示报告位置

-
可以直接打开

前置和后置方法
类级别的前置和后置
在整个测试类执行过程中, 所有用例执行之前执行一次前置方法, 所有用例执行结束,执行一次后置方法
class 测试类名:
def setup_class(self):
类前置,一个类中所有用例执行之前,执行一次
def teardown_class(self):
类后置,一个类中所有用例执行之后,执行一次
方法级别的前置和后置
每个测试方法执行前后都会自动调用
class 测试类名:
def setup(self):
方法前置,每个测试方法执行之前,执行
def teardown(self):
方法后置,每个测试方法执行之后执行
例子:
class TestLogin:
def setup_class(self):
print('1. 打开浏览器')
def teardown_class(self):
print('5. 关闭浏览器')
def setup(self):
print('2. 打开登录页面')
def teardown(self):
print('4. 关闭退出登录页面')
def test_login1(self):
print(f"3.输入用户名1,密码1,验证码1,点击登录")
def test_login2(self):
print(f"3.输入用户名2,密码2,验证码2,点击登录")
def test_login3(self):
print(f"3.输入用户名3,密码3,验证码3,点击登录")

前置和后置方法, 在今后的工作中,根据实际用例的需要,去选择,不用同时出现
还是要多写代码啊,加油!!!

浙公网安备 33010602011771号