pytest是一个功能非常全面的Python自动化测试框架
特点:
1、简单灵活,支持参数化,可以细粒度的控制测试用例;
2、不仅支持简单的单元测试,还支持复杂的功能测试,不仅可以用来做selenium/appium的UI自动化测试,还可以用作做基于Python+requests的接口自动化测试;
3、第三方插件非常丰富,如pytest-selenium(集成了selenium)、pytest-html(完美的html测试报告)、pytest-reunfailures(失败case重复测试)等;
4、测试用例跳跃式(skip)执行以及标记后选择性处理(mark);
5、很好的与CI工具(jenkins)结合;
编写规则:
1、测试文件以test_开头,以_test结尾也可以;
2、测试类以Test开头,并且不能带有__init__方法;
3、测试函数(方法)以test_开头;
4、断言使用assert;
一、安装pytest
$ pip install pytest
二、执行一个测试
测试通过
# test_demo8.py def test_pass(): assert 1 == 1
通过pytest来运行上面测试函数
在pycharm的Terminal中直接输入命令pytest test_demo8.py执行
MacBook-Pro:test_demo fyuanyuan$ pytest test_demo8.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 1 item
test_demo8.py . [100%]
========================================================================================== 1 passed in 0.01s ===========================================================================================
执行结果为test_demo8.py测试通过(pytest使用 . 标识测试通过PASSED)
下面使用-v选项来展示测试的详细信息
MacBook-Pro:test_demo fujinjie$ pytest -v test_demo8.py ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 1 item test_demo8.py::test_passing PASSED [100%] ========================================================================================== 1 passed in 0.01s ===========================================================================================
测试失败
# test_demo8.py def test_fail(): assert 1 ==2
同样在命令行执行pytest test_demo8.py命令
MacBook-Pro:test_demo fujinjie$ pytest test_demo8.py ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 1 item test_demo8.py F [100%] =============================================================================================== FAILURES =============================================================================================== _____________________________________________________________________________________________ test_failing _____________________________________________________________________________________________ def test_fail(): > assert 1 == 2 E assert 1 == 2 test_demo8.py:8: AssertionError ========================================================================================== 1 failed in 0.05s ===========================================================================================
测试结果为失败,pytest使用 F 来标识测试失败FAILED
pytest中使用assert来进行断言。
三、标记函数
pytest默认查找当前目录下所有以test开始或者结尾的Python文件,并执行其中所有以test开始或结束的函数(方法)
run.py
#--coding:utf-8 --
#run.py
import pytest if __name__ == '__main__': pytest.main(['-v'])
test_demo9.py
#--coding:utf-8 -- #test_demo9.py def test_demo9_func1(): assert 1 == 1 def test_demo9_func2(): assert 2 == 2
test_demo10.py
#--coding:utf-8 -- #test_demo10.py def test_demo10_func3(): assert 3 == 3 def test_demo10_func4(): assert 4 == 4
因为run.py/test_demo9.py/test_demo10.py在同一个demo目录下,所以执行run.py时pytest会查找该目录下所有以test开头或结尾的Python文件,并执行文件中所有以test开头或结尾的函数和方法
============================= test session starts ============================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo/templates/demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collecting ... collected 4 items test_demo10.py::test_demo10_func3 PASSED [ 25%] test_demo10.py::test_demo10_func4 PASSED [ 50%] test_demo9.py::test_demo9_func1 PASSED [ 75%] test_demo9.py::test_demo9_func2 PASSED [100%] ============================== 4 passed in 0.02s ===============================
由于某些原因,我只想执行test_demo9_func2()测试用例看是否通过,通过pytest有以下几种方法:
方法一,执行时指定函数名,通过 :: 标记
#--coding:utf-8 -- #run.py import pytest if __name__ == '__main__': pytest.main(['test_demo9.py::test_demo9_func2','-v'])
或者在命令行中输入
$pytest -v demo/test_demo9.py::test_demo9_func2
运行结果
MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo9.py::test_demo9_func2 ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 1 item demo/test_demo9.py::test_demo9_func2 PASSED [100%] ========================================================================================== 1 passed in 0.01s ===================================================
方法二,使用 -k 选项标识来模糊匹配
匹配执行demo目录下名称中含有func2的测试用例
$ pytest -v -k func2 demo/
执行结果
MacBook-Pro:test_demo fujinjie$ pytest -v -k func2 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 4 items / 3 deselected / 1 selected demo/test_demo9.py::test_demo9_func2 PASSED [100%] =================================================================================== 1 passed, 3 deselected in 0.01s =========================================
以上两种方法,第一种只能指定一个测试用例,无法批量执行;第二种需要所有测试名称包含相同的部分名称是才能批量执行。
方法三,直接使用 pytest.mark 在函数(测试用例)上进行标记
#--coding:utf-8 -- #test_demo9.py import pytest @pytest.mark.run def test_demo9_func1(): assert 1 == 1 @pytest.mark.unrun def test_demo9_func2(): assert 2 == 2
#--coding:utf-8 -- #test_demo10.py import pytest @pytest.mark.unrun def test_demo10_func3(): assert 3 == 3 @pytest.mark.unrun def test_demo10_func4(): assert 4 == 4
在命令行输入 pytest -v -m run demo/ 命令执行
MacBook-Pro:test_demo fujinjie$ pytest -v -m run demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 4 items / 3 deselected / 1 selected demo/test_demo9.py::test_demo9_func1 PASSED [100%] =========================================================================================== warnings summary ==========================
上述4个测试函数,只有被标记为run的 test_demo9_func1( ) 被执行
注:一个函数可以被添加多个标记,多个函数可以添加相同的标记来实现批量执行
运行时 -m 后面可加逻辑
#--coding:utf-8 -- #test_demo9.py import pytest @pytest.mark.run def test_demo9_func1(): assert 1 == 1 @pytest.mark.commit @pytest.mark.unrun def test_demo9_func2(): assert 2 == 2
执行 pytest -v -m "unrun and commit" demo/
MacBook-Pro:test_demo fujinjie$ pytest -v -m "unrun and commit" demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 4 items / 3 deselected / 1 selected demo/test_demo9.py::test_demo9_func2 PASSED [100%]
被标记为 unrun 和 commit 的测试函数才执行
四、跳过测试
在测试工作中面对大批量的测试用例,想对其中某一条跳过不执行,Pytest中使用 pytest.mark.skip 可直接跳过该测试用例
#--coding:utf-8 -- #test_demo10.py import pytest @pytest.mark.skip def test_demo10_func3(): assert 3 == 3 def test_demo10_func4(): assert 4 == 4
在命令行执行 pytest -v demo/test_demo10.py
MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo10.py ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 2 items demo/test_demo10.py::test_demo10_func3 SKIPPED [ 50%] demo/test_demo10.py::test_demo10_func4 PASSED [100%] ===================================================================================== 1 passed, 1 skipped in 0.01s =============================================
执行结果中只有 test_demo10_func4 被执行,test_demo10_func3 直接跳过没执行
五、参数化
当对一个函数进行测试时,通常会给这个函数传递多组参数,模拟各种不同情况,在pytest中就是参数化测试,即每组参数都独立执行一次测试,使用 pytest.mark.parametrize(argnames, argvalues)
#--coding:utf-8 -- #test_demo11.py import pytest @pytest.mark.parametrize('password',['12345','123456a','abcdefgh']) def test_demo_func5(password): assert len(password) >= 6
在命令行执行 pytest -v demo/test_demo11.py
MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo11.py ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 3 items demo/test_demo11.py::test_demo_func5[12345] FAILED [ 33%] demo/test_demo11.py::test_demo_func5[123456a] PASSED [ 66%] demo/test_demo11.py::test_demo_func5[abcdefgh] PASSED [100%] =============================================================================================== FAILURES =============================================================================================== ________________________________________________________________________________________ test_demo_func5[12345] ________________________________________________________________________________________ password = '12345' @pytest.mark.parametrize('password',['12345','123456a','abcdefgh']) def test_demo_func5(password): > assert len(password) >= 6 E AssertionError: assert 5 >= 6 E + where 5 = len('12345') demo/test_demo11.py:8: AssertionError
通过上述结果可以看出该测试函数被执行了3次,每次都以不同的password参数传入,FAILLED一次,PASSED两次。
传入多个参数
#--coding:utf-8 -- #test_demo11.py import pytest @pytest.mark.parametrize('user,password',[('Jack','123456'),('Pluo','123456a'),('Flak','abcdefg')]) def test_demo11_func6(user,password): db = {'Jack':'123456', 'Pluo':'123456a', 'Flak':'abcdefg'} assert db[user] == password
在命令行执行 pytest -v demo/test_demo11.py::test_demo11_func6
MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo11.py::test_demo11_func6 ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 3 items demo/test_demo11.py::test_demo11_func6[Jack-123456] PASSED [ 33%] demo/test_demo11.py::test_demo11_func6[Pluo-123456a] PASSED [ 66%] demo/test_demo11.py::test_demo11_func6[Flak-abcdefg] PASSED [100%] ========================================================================================== 3 passed in 0.02s ===========================================================================================
六、固件Fixture
Fixture是一些函数,pytest会在执行测试函数(用例)之前或之后加载执行它们,比如执行测试函数前数据库的连接和执行完毕后数据库的关闭操作。
Pytest通过 @pytest.fixture() 来定义固件,在pytest中使用conftest.py集中管理固件,更大程度上复用(conftest.py的作用域为其所在的目录和子目录)
conftest.py在demo目录下,因此它的作用域为demo目录下的所有文件以及子文件
conftest.py
#--coding:utf-8 -- #conftest.py import pytest @pytest.fixture() def fixture_func1(): return '3721'
test_demo11.py
#--coding:utf-8 -- #test_demo11.py import pytest def test_demo11_func7(fixture_func1): num = '3721' assert num == fixture_func1
在 test_demo11.py 中测试函数 test_demo11_func7 直接调用 conftest.py 中的 fixture_func1 固件完成测试
注意:不要显示调用 conftest.py (pytest会根据conftest.py的作用域自动调用),可以把 conftest.py 当作插件来理解。
在命令行执行 pytest -v -k func7 demo/test_demo11.py
MacBook-Pro:test_demo fujinjie$ pytest -v -k func7 demo/test_demo11.py ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7 cachedir: .pytest_cache metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}} rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 7 items / 6 deselected / 1 selected demo/test_demo11.py::test_demo11_func7 PASSED [100%] =================================================================================== 1 passed, 6 deselected in 0.02s ====================================================================================
七、预处理和后处理
在测试过程中,我们需要在测试开始之前做准备工作,以及在测试结束后做收尾工作,在pytest中通过固件来自动化所有预处理和后处理,使用 yield 关键字将固件分为两部分,yield 之前的代码属于预处理,在测试之前执行,yield 之后的代码属于后处理,将在测试完成后执行。
在 conftest.py 中加入 fixture_func2 固件
#--coding:utf-8 -- #conftest.py import pytest @pytest.fixture() def fixture_func1(): return '3721' @pytest.fixture() def fixture_func2(): print('测试开始之前') yield print('测试结束之后')
在 test_demo11.py 的测试函数 test_demo11_func7 中调用固件 fixture_func1 和 fixture_func2
def test_demo11_func7(fixture_func1,fixture_func2): num = '3721' assert num == fixture_func1
在命令行中执行 pytest --setup-show -s -k func7 demo/
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -s -k func7 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 11 items / 10 deselected / 1 selected demo/test_demo11.py SETUP F fixture_func1测试开始之前 SETUP F fixture_func2 demo/test_demo11.py::test_demo11_func7 (fixtures used: fixture_func1, fixture_func2).测试结束之后 TEARDOWN F fixture_func2 TEARDOWN F fixture_func1 =================================================================================== 1 passed, 10 deselected in 0.02s ===================================================================================
八、作用域
pytest使用作用域来进行指定固件的使用范围
定义固件时通过 scope 参数声明作用域,可选项有:
1、function: 函数级,每个测试函数都会执行一次固件;
2、class:类级别,每个测试类执行一次,所有方法都可以使用;
3、module:模块级,每个模块执行一次,模块内函数和方法都可以使用;
4、session:会话级,一次测试只执行一次,所有被找到的函数和方法都可用。
注:固件默认的作用域为 function
conftest.py
@pytest.fixture(scope='function') def fixture_function(): pass @pytest.fixture(scope='module') def fixture_module(): pass @pytest.fixture(scope='session') def fixture_session(): pass @pytest.fixture(scope='class') def fixture_class(): pass
test_demo11.py
def test_demo11_func8(fixture_function,fixture_session,fixture_module):
pass
在命令行执行 pytest --setup-show -k func8 demo/ 可以看到各固件的作用域与执行顺序
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func8 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 12 items / 11 deselected / 1 selected demo/test_demo11.py SETUP S fixture_session SETUP M fixture_module SETUP F fixture_function demo/test_demo11.py::test_demo11_func8 (fixtures used: fixture_function, fixture_module, fixture_session). TEARDOWN F fixture_function TEARDOWN M fixture_module TEARDOWN S fixture_session =================================================================================== 1 passed, 11 deselected in 0.02s ============================================================
对于类使用作用域,需要使用 @pytest.mark.usefixtures
test_demo11.py
@pytest.mark.usefixtures('fixture_class') class TestDemo11Class1: def test_demo11_func9(self): pass def test_demo11_func10(self): pass
在命令行执行 pytest --setup-show -k TestDemo11Class1 demo/ 结果如下
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k TestDemo11Class1 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 14 items / 12 deselected / 2 selected demo/test_demo11.py SETUP C fixture_class demo/test_demo11.py::TestDemo11Class1::test_demo11_func9 (fixtures used: fixture_class). demo/test_demo11.py::TestDemo11Class1::test_demo11_func10 (fixtures used: fixture_class). TEARDOWN C fixture_class =================================================================================== 2 passed, 12 deselected in 0.04s ===================================================================================
上述结果可见,该类下的所有测试函数都在这个类级别固件作用范围内
九、自动执行
上述固件,都是通过我们手动指定后才执行的,在pytest中可以在定义固件时指定 autouse 参数让固件自动执行
conftest.py
@pytest.fixture(scope='function',autouse=True) def fixture_function(): pass @pytest.fixture(scope='module',autouse=True) def fixture_module(): pass @pytest.fixture(scope='session',autouse=True) def fixture_session(): pass
test_demo11.py
def test_demo11_func11():
pass
命令行执行 pytest --setup-show -k func11 demo/
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func11 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 15 items / 14 deselected / 1 selected demo/test_demo11.py SETUP S fixture_session SETUP M fixture_module SETUP F fixture_function demo/test_demo11.py::test_demo11_func11 (fixtures used: fixture_function, fixture_module, fixture_session). TEARDOWN F fixture_function TEARDOWN M fixture_module TEARDOWN S fixture_session =================================================================================== 1 passed, 14 deselected in 0.02s ===================================================================================
结果可见,所有参数 autouse = True 的 fixture 都自动执行了
十、对固件重命名
fixture默认的名称为定义是的函数名称,可以通过 name 选项指定名称
conftest.py
@pytest.fixture(name='year') def fixture_year(): return 2020
test_demo11.py
def test_demo11_func12(year): now_year = 2020 assert now_year == year
执行结果可见,固件名称被命名为 year,可供测试函数直接调用
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func12 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 16 items / 15 deselected / 1 selected demo/test_demo11.py SETUP F year demo/test_demo11.py::test_demo11_func12 (fixtures used: year). TEARDOWN F year =================================================================================== 1 passed, 15 deselected in 0.02s ===================================================================================
十一、固件参数化
通过固件调用不同的参数,使测试函数应用与不同的测试场景,提高测试函数的复用性
固件参数化需要使用 pytest 内置的固件 request,并通过 request.param 获取参数
# conftest.py @pytest.fixture(params=[('参数k1','参数v1'),('参数k2','参数v2'),('参数k3','参数v3')]) def param(request): return request.param @pytest.fixture(autouse=True) def fixture_param(param): print('正在传入参数%s:%s'% param) yield print('参数%s:%s处理完毕'% param)
在test_demo11.py中加入test_demo11_func13 测试函数
def test_demo11_func13():
pass
执行结果
MacBook-Pro:test_demo fujinjie$ pytest --setup-show -s -k func13 demo/ ========================================================================================= test session starts ========================================================================================== platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: /Users/fujinjie/PycharmProjects/test_demo plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0 collected 51 items / 48 deselected / 3 selected demo/test_demo11.py SETUP F param[('参数k1', '参数v1')]正在传入参数参数k1:参数v1 SETUP F fixture_param (fixtures used: param) demo/test_demo11.py::test_demo11_func13[param0] (fixtures used: fixture_param, param, request).参数参数k1:参数v1处理完毕 TEARDOWN F fixture_param TEARDOWN F param[('参数k1', '参数v1')] SETUP F param[('参数k2', '参数v2')]正在传入参数参数k2:参数v2 SETUP F fixture_param (fixtures used: param) demo/test_demo11.py::test_demo11_func13[param1] (fixtures used: fixture_param, param, request).参数参数k2:参数v2处理完毕 TEARDOWN F fixture_param TEARDOWN F param[('参数k2', '参数v2')] SETUP F param[('参数k3', '参数v3')]正在传入参数参数k3:参数v3 SETUP F fixture_param (fixtures used: param) demo/test_demo11.py::test_demo11_func13[param2] (fixtures used: fixture_param, param, request).参数参数k3:参数v3处理完毕 TEARDOWN F fixture_param TEARDOWN F param[('参数k3', '参数v3')] =================================================================================== 3 passed, 48 deselected in 0.04s ============================================
注意:与函数参数化 @pyest.mark.parametrize 不同,固件是在定义时使用 params 进行参数化,固件参数化依赖内置的 request 以及属性 param