最近工作中用到了pytest,总结一些用法:
1. 安装:
pip install pytest
2. 运行:
pytest 默认只能识别以test_
开头的文件和测试用例,如果pytest后面不带文件名,则默认执行当前目录下所有以test_
开头的文件。
- 执行某个文件里所有以 test 开头的用例:
pytest test_demo.py
# test_demo.py def test_01(): assert 1+1 == 2 def test_02(): assert 1+3 == 4
执行结果:
$ pytest test_demo.py
========================================= test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items
test_demo.py .. [100%]
======================================== 2 passed in 0.04 seconds =========================================
如果只想执行test_01,可以使用pytest test_demo.py::test_01
- 如果用例是用类组织起来的:
# test_class.py class TestClass(object): def test_one(self): x = "this" assert 'h' in x def test_two(self): x = "hello" assert hasattr(x, 'check')
执行结果:
$ pytest test_class.py =========================================== test session starts ============================================ platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 rootdir: /Users/libo/python3workspace/learn, inifile: plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1 collected 2 items test_class.py .F [100%] ================================================= FAILURES ================================================= ____________________________________________ TestClass.test_two ____________________________________________ self = <test_class.TestClass object at 0x102f46780> def test_two(self): y = "world" > assert 'h' in y E AssertionError: assert 'h' in 'world' test_class.py:9: AssertionError ========================================== 1 failed, 1 passed in 0.08 seconds ====================================
如果一个文件里有多个类,你只想执行其中一个类里的用例:
pytest test_class.py::TestClass
- 执行某个文件夹下所有的以
test_
开头的文件:pytest testcase/
# testcase/test_demo01.py def test_one(): x = 'this' assert 'h' in x # testcase/test_demo02.py def test_two(): y = 'world' assert 'h' in y
执行结果:
$ pytest testcase/ ========================================== test session starts ============================================ platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 rootdir: /Users/libo/python3workspace/learn, inifile: plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1 collected 2 items testcase/test_demo01.py . [ 50%] testcase/test_demo02.py F [100%] ============================================== FAILURES =========================================== _________________________________________________ test_two _________________________________________________ def test_two(): y = 'world' > assert 'h' in y E AssertionError: assert 'h' in 'world' testcase/test_demo02.py:3: AssertionError ==================================== 1 failed, 1 passed in 0.09 seconds ================================
- 执行带某个标记的用例,比如用例中带了
@pytest.mark.smoke
标记的用例:
# test_mark.py @pytest.mark.smoke def test_01(): assert 1+1 == 2 def test_02(): assert 1+3 == 4
$ pytest -m smoke test_mark.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items / 1 deselected / 1 selected
test_mark.py . [100%]
================================== 1 passed, 1 deselected in 0.03 seconds ==================================
可以看到只执行带@pytest.mark.smoke
的用例。
- 按用例函数的名称来执行:
pytest -k 01 test_mark.py
$ pytest -k 01 test_mark.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items / 1 deselected / 1 selected
test_mark.py . [100%]
================================== 1 passed, 1 deselected in 0.01 seconds ==================================
按照用例名字来执行,只执行名字里含有01的测试用例。
3. pytest fixture
@pytest_fixture
的作用是提供一个固定的参数给测试重复的使用,相当于unittest里的setup
和teardown
.
- pytest fixture 做函数的参数
# test_fixture.py @pytest.fixture(scope="module") def num(): n = random.randint(1, 5) return n def test_01(num): print(num) assert 0 def test_02(num): print(num) assert 0
- pytest fixture的scope有class, session 和 module.
- 此时执行可以多次执行看看两个函数里num的数值是否是一样:
$ pytest test_fixture.py =========================================== test session starts ============================================ platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 rootdir: /Users/libo/python3workspace/learn, inifile: plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1 collected 2 items test_fixture.py FF [100%] ================================================= FAILURES ================================================= _________________________________________________ test_01 __________________________________________________ num = 3 def test_01(num): print(num) > assert 0 E assert 0 test_fixture.py:12: AssertionError ------------------------------------------- Captured stdout call ------------------------------------------- 3 _________________________________________________ test_02 __________________________________________________ num = 3 def test_02(num): print(num) > assert 0 E assert 0 test_fixture.py:16: AssertionError --------------------------------