什么是Pytest?
python的第三方库,与标准库unittest测试框架类似,但是比unittest框架使用起来更加简洁,灵活,效率更高
当前比较流行的测试框架
- Robot Framework
- Pytest
- UnitTest/PyUnit
pytest 和unittest
unittest | pytest | |
---|---|---|
用例编写规则 | 1)测试文件必须先import unittest 2)测试类必须继承unittest.TestCase 3)测试方法必须以“test_”开头 4)测试类必须要有unittest.main()方法 | 1)测试文件名必须以“test_”开头或者"test"结尾(如:test_ab.py) 2)测试方法必须以“test”开头 3)测试类命名以"Test"开头 |
用例分类执行 | 默认执行全部用例,也可以通过加载testsuit,执行部分用例 | 可以通过@pytest.mark来标记类和方法,pytest.main加入参数("-m")可以只运行标记的类和方法 |
用例前置和后置 | 提供了setUp/tearDown,只能针对所有用例 | pytest中的fixture显然更加灵活。可以任意自定义方法函数,只要加上@pytest.fixture()这个装饰器,那么被装饰的方法就可以被使用 |
参数化 | 需依赖ddt库 | 使用@pytest.mark.parametrize装饰器 |
断言 | 很多断言格式(assertEqual、assertIn、assertTrue、assertFalse) | 只有assert一个表达式,用起来比较方便 |
报告 | 使用HTMLTestRunnerNew库 | 有pytest-HTML、allure插件 |
失败重跑 | 无此功能 | pytest支持用例执行失败重跑,pytest-rerunfailures插件 |
Pytest
特点
- 简单灵活,容易上手
- 支持参数化
- 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)
- pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
- 测试用例的skip和xfail处理
- 可以很好的和jenkins集成
- report框架----allure 也支持了pytest
安装
pip install pytest
如何编写pytest测试样例?
- 1、文件名为
test_*.py
或者*_test.py
- 2、以
Test
开头的类 - 3、以
test_
开头的函数 - 4、包
package
里面要有__init__.py
运行模式
命令行运行所有case
1、运行所有测试用例
pytest
2、运行后生成测试报告
安装pytest-html
pip install pytest-html
运行
pytest --html=report.html
运行指定的case
1、直接运行test_case.py文件中的所有case
pytest test_case01.py
2、运行test_case.py文件中的TestCase class下的全部case
pytest case_test.py::TestCase
3、运行test_case.py文件中的TestCase class下的指定的case
pytest case_test.py::TestCase::test_case_002
多线程运行case
安装pytest-xdist
pip install pytest-xdist
运行(NUM并发的进程数)
pytest -n NUM
重运行机制-命令行运行
安装pytest-rerunfailures
pip install pytest-rerunfailures
运行
pytest --reruns 重试次数 --reruns-delay 次数之间的延时设置(单位:秒)
pytest.main(['--reruns', '3', '--reruns-delay', '5'])
pytest test_case01.py --reruns NUM
命令行参数
1) -v:pytest -v 可以输出用例更加详细的执行信息(用例所在文件及用例名称)
2)-s:pytest -s 输出用例中的调试信息(print()打印)
3)-m:pytest -m “标记” 执行特定的测试用例(标示)
注册标记-pytest.ini
(不注册也可以但是有警报,编码要用GBK)
[pytest]
markers =
run_case: 注册run_case标记
run_case2
run_case3
例子:
@pytest.mark.run_case
def test_case_004():
assert 2 == 3
@pytest.mark.run_case2
def test_case_005():
assert 2 == 3
@pytest.mark.run_case3
def test_case_006():
assert 2 == 3
@pytest.mark.run_case
def test_case_007():
assert 2 == 3
pytest test_case03.py -m "run_case"
运行多个标记(标记之间用or)
pytest test_case03.py -m "run_case or run_case2"
4)-k:pytest -k “关键字” 执行用例包含"关键字"的用例
pytest test_case03.py -k "007"
运行多个指定key(使用or)
pytest test_case03.py -k "007 or 006"
5)-q:pytest -q 简化控制台的输出
扩展
1、夹具
因为pytest中没有了setup teardown ,所以引入了一个新的名词,夹具
优势
- 命名方式灵活,不局限于setup和teardown这几个命名
- conftest.py 配置里可以实现数据共享,不需要import就能自动找到配置
- scope=“module” 可以实现多个.py跨文件共享前置, 每一个.py文件调用一次
- scope=“session” 以实现多个.py跨文件使用一个session来完成多个用例
- 多个测试用例可以调用同一个fixture功能
@pytest.fixture()
在同一文件下的夹具
@pytest.fixture()
def setUp():
print("在用例执行之前执行")
yield
print("在用例执行之后执行")
第一种:直接把夹具当做参数传进去
第二种:使用@pytest.mark.usefixtures("setUp")
@pytest.mark.usefixtures("setUp")
def test_case_009():
print("测试用例函数:test_case_009")
assert 2 == 2
缺点
如果别的文件也需要跟此功能的夹具一样,那么就需要重复的创建夹具
为解决上面的确定,我们可以使用共享夹具conftest.py
(共享夹具文件必须为这个名字)
@pytest.fixture函数的scope的作用域:
- function,表示fixture函数在测试方法执行前和执行后执行一次。
- class,表示fixture函数在测试类执行前和执行后执行一次。
- module,表示fixture函数在测试脚本执行前和执行后执行一次。
- package,表示fixture函数在测试包(文件夹)中第一个测试用例执行前和最后一个测试用例执行后执行一次。
- session,表示所有测试的最开始和测试结束后执行一次。
2、数据驱动
@pytest.mark.parametrize("case", cases)
- 1、第一个参数是字符串,多个参数中间用逗号隔开
- 2、第二个参数是list,多组数据用元祖类型;传三个或更多参数也是这样传。list的每个元素都是一个元组,元组里的每个元素和按参数顺序一一对应
- 3、传一个参数 @pytest.mark.parametrize(‘参数名’,list) 进行参数化
- 4、传两个参数@pytest.mark.parametrize(‘参数名1,参数名2’,[(参数1_data[0], 参数2_data[0]),(参数1_data[1], 参数2_data[1])]) 进行参数化
注意: 如果第二个参数list为空的时候,会自动跳过skipped
3、跳过用例
@pytest.mark.skip()
@pytest.mark.skipif()
运行的时候加上-rs
才会把跳过原因显示出来
例子:
@pytest.mark.skip("跳过此用例")
def test_case01():
a = 1
b = 2
assert a == b
@pytest.mark.skipif(1 == 1, reason="如果满足条件的时候才会跳过")
def test_case02():
assert 1 == 1
@pytest.mark.skipif(1 == 2, reason="如果满足条件的时候才会跳过")
def test_case03():
assert 1 == 2
4、失败重运行-使用装饰器
@pytest.mark.flaky(reruns=重试次数, reruns_delay=次数之间的延时设置(单位:秒))
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_case_014():
assert 2 == 3
5、运行进度条显示
pip install pytest-sugar