单元测试框架pytest

前提

pytest是一个非官方的单元测试框架,需要先进行安装。所以pip一下

技术点

一、运行参数(进入到相应目录)

1、无参数运行

运行目录下的所有py文件:pytest
运行目录下某一个py文件:pytest test_01.py
运行目录下py文件中的某个类:pytest test_02.py::TestClass
运行目录下py文件中某个类的某个方法:pytest test_02.py::TestClass::test_one
指定目录运行:pytest testpy

2、-v参数

打印详细的日志信息

3、-s参数

代码里面有 print 输出语句,想在运行结果中打印 print 输出

4、-k参数

pytest -k '类名' //运行指定的类
pytest -k '方法名' //运行指定的方法
pytest -k '类名 and not 方法名' //运行类里的方法,不包含某个方法

5、-x参数

遇到失败用例立即停止运行

6、--maxfail参数

用例失败个数达到阀值后停止运行
pytest --maxfail 2 test_02.py

7、-m参数

只运行标记 @pytest.mark.[标记名]的方法和类

比如类名上添加:

@pytest.mark.oneone,

执行命令:pytest -m "oneone" test_02.py

如果有多个标记可以用 and 或 or 进行组合

8、--durations参数

获取执行最慢的一个:pytest --durations=1

9、--collect-only参数

只收集用例不执行,可用于统计用例数

二、pytest框架结构

 1 import pytest
 2 
 3 def setup_module():
 4     print("
setup_module,只执行一次,当有多个测试类的时候使用")
 5 def teardown_module():
 6     print("
teardown_module,只执行一次,当有多个测试类的时候使用")
 7 
 8 
 9 # setup_function teardown_function作用于类外的函数
10 def setup_function():
11     print("
setup_function")
12 def teardown_function():
13     print("
setup_function")
14 
15 def test_cls_out():
16     print("类外的函数方法")
17 
18 
19 class TestPytest1:
20     def setup_class(self):
21         print("
setup_class1,只执行一次,当有多个测试方法的时候使用")
22     def teardown_class(self):
23         print("
teardown_class1,只执行一次,当有多个测试方法的时候使用")
24 
25 
26     def setup_method(self):
27         print("
setup_method1,每个测试方法都执行一次")
28     def teardown_method(self):
29         print("teardown_method1,每个测试方法都执行一次")
30 
31 
32     def setup(self):
33         print("setup")
34     def teardown(self):
35         print("teardown")
36 
37 
38     def test_three(self):
39         print("test_three,测试用例")
40 
41     def test_four(self):
42         print("test_four,测试用例")

三、控制执行顺序

安装:pip install pytest-ordering
负数越小越先执行(-100,-18,-1)
正数越小越先执行(1,18,100)

 1 import pytest
 2 
 3 
 4 class Testpy:
 5     @pytest.mark.run(order=1)
 6     def test_one(self):
 7         print(111)
 8 
 9     @pytest.mark.run(order=18)
10     def test_two(self):
11         print(222)
12 
13     @pytest.mark.run(order=100)
14     def test_three(self):
15         print(333)

四、并发执行

安装:pip install pytest-xdist
多个CPU并行执行用例,如果参数为 auto 自动检测系统的 CPU 数目;如果参数为数字,则指定运行测试的处理器进程数。
pytest -n auto
pytest -n [num]

五、pytest-html 生成测试报告

安装:pip install pytest-html
指定报告的存放路径
--html=./report/report.html
 加这个参数生成的报告css不是独立的
 --self-contained-html

六、assert断言

assert a
assert a == b
assert a in b
assert not a
assert a != b (a <> b一般不再使用)

七、@pytest.fixture

fixture 有一个参数 scope,通过 scope 可以控制 fixture 的作用范围,根据作用范围大小划分:session> module> class> function
具体作用范围如下:
  function 函数或者方法级别都会被调用(默认)
  class 类级别调用一次
  module 模块级别调用一次
  session 是多个文件调用一次(可以跨.py文件调用,每个.py文件就是module)

1、以参数的形式传入到方法里执行

 1 import pytest
 2 
 3 @pytest.fixture()
 4 def login():
 5     print("登录需要的操作步骤")
 6 
 7 @pytest.fixture()
 8 def operate():
 9     print("用例的执行步骤")
10 
11 @pytest.fixture()
12 def xiao():
13     print("1234567890")
14 
15 # 需要在函数中传入函数名,函数上需要先标记上 @pytest.fixture()
16 def test_case1(login, operate, xiao):
17     print("test_case1,需要登录执行完毕")

2、fixture的两种引用方式

 1 import pytest
 2 
 3
 4 @pytest.fixture()
 5 def open():
 6     print("打开浏览器")
 7     yield
 8 
 9     print("执行teardown !")
10     print("最后关闭浏览器")
11 
12 
13 # 方式一:装饰器方式引用
16 @pytest.mark.usefixtures("open")
17 def test_search1():
18     print("test_search1")
19     # raise NameError
20     pass
21 
22 
23 # 方式二:在函数中传入
26 def test_search2(open):
27     print("test_search2")
28     # raise NameError
29     pass

3、conftest.py应用
conftest.py等同于scope=session
pytest test_scope1.py test_scope2.py

相应代码见:https://github.com/hanshoukai/pytest_fixture

fixture为function

fixture为class

 

 fixture为module

  fixture为session

4、自动执行fixture装饰下的函数
conftest.py中标记为:@pytest.fixture(autouse="true")

每个测试函数都会自动调用该前置函数


5、fixture传递参数

1 import pytest
2 
3 @pytest.fixture(params=[1, 2, 3])
4 def params(request):
5     return request.param
6 
7 def test_com(params):
8     print(f"测试数据:{params}")
9     assert params < 5


八、@pytest.mark.parametrize参数化

传一个参数

1 # 传一个参数
2 @pytest.mark.parametrize("user", ["13552977251", "13552554252"])
3 def test_user(user):
4     print(user)

传两个参数

@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+5", 7), ("7*5", 35)])
如上 "test_input,expected" 可以修改为 列表或者元组 的形式
列表:@pytest.mark.parametrize(["test_input","expected"], [("3+5", 8), ("2+5", 7), ("7*5", 35)])
元组:@pytest.mark.parametrize(("test_input","expected"), [("3+5", 8), ("2+5", 7), ("7*5", 35)])
1 # 传两个参数
2 @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+5", 7), ("7*5", 35)])
3 def test_function(test_input, expected):
4     # eval可以将字符串转成3+5的表达方式
5     print(test_input, expected)
6     assert eval(test_input) == expected

传三个参数 三组数据,ids是别名必须与参数的数量保持一致

参数组合

1 # 参数组合
2 @pytest.mark.parametrize("x", [1, 2])
3 @pytest.mark.parametrize("y", [3, 4, 5])
4 def test_num(x, y):
5     # print(f"测试数据组合x: {x} , y:{y}")
6     print("测试数据组合x:"+str(x)+" y:"+str(y))

函数返回值类型

1 # 函数返回值类型
2 def return_data():
3     return [(1, 2), (3, 4)]
4 
5 @pytest.mark.parametrize("a,b", return_data())
6 def test_data(a, b):
7     print(a)
8     print(b)

用yaml文件做为参数化的数据源

companyid.yaml

-
  - 23725503
  - 24721214
  - 2352987806

data.yaml

-
  - 20
  - 30
-
  - 40
  - 50

脚本:

 1 import pytest
 2 import yaml
 3 
 4 
 5 @pytest.mark.parametrize('a, b', yaml.safe_load(open("data.yaml", encoding='utf-8')))
 6 # @allure.step("方法的描述信息")
 7 def test_fo(a, b):
 8     print(a)
 9     print(b)
10 
11 
12 @pytest.mark.parametrize('company_id', yaml.safe_load(open("companyid.yaml", encoding='utf-8')))
13 # @allure.step("方法的描述信息")
14 def test_foo(company_id):
15     print("企业ID:", company_id)

九、pytest.ini模板

 1 [pytest]
 2 # 空格分隔,可添加多个命令行参数  重试两次每隔5秒  生成报告
 3 addopts = -sv --reruns 2 --reruns-delay 5 --html=./report/report.html --self-contained-html
 4 #addopts = -s -v --alluredir=./result
 5 # 当前目录下
 6 testpaths = ./testcase/
 7 #配置测试搜索的文件名称,当前目录下以test开头,以.py结尾的所有文件
 8 python_files = test*.py
 9 #配置测试搜索的测试类名,当前目录下以Test开头的所有类
10 python_classes = Test
11 #配置测试搜索的测试类名,当前目录下以test_开头的所有方法
12 python_functions = test_*

十、更多插件

用例失败后自动重新运行:pytest-rerunfailures

使用方法:pytest test_x.py --reruns=2 --reruns-delay 5  #失败后重试2次,每次间隔5秒

在脚本中指定定义重跑的次数,这个时候在运行的时候,就无需加上 --reruns 这个参数

1 @pytest.mark.flaky(reruns=6, reruns_delay=2)
2 def test_example(self):
3     print(3)
原文地址:https://www.cnblogs.com/hanxiaobei/p/13750067.html