运行pytest可以指定目录和文件,如果不指定,pytest会搜索当前目录及其子目录中以test_开头或以_test结尾得测试函数。我们把pytest搜索测试文件和测试用例的过程称为测试搜索(test discovery)。只要遵循pytest的命名规则,pytest就能自动搜索所有待执行的测试用例。
1、测试文件命名规则,test_xxx.py或xxx_test.py
2、方法、测试函数命名规则,test_xxx
3、测试类命名规则,Testxxx,并且不能带有 init 方法
项目目录:
test_01/test_01.py代码如下:
#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):def test_login_01(self):"""用例1"""print('执行用例test_login_01断言1')pytest.assume(1 == 1)print('执行用例test_login_01断言2')pytest.assume(2 == 2)def test_login_02(self):"""用例2"""print('执行用例test_login_02断言1')pytest.assume(3 == 3)print('执行用例test_login_02断言2')pytest.assume(True)
test_01/test_02.py代码如下:
#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):def test_login_03(self):"""用例1"""print('执行用例test_login_03断言1')pytest.assume(1 == 1)print('执行用例test_login_03断言2')pytest.assume(2 == 2)def test_login_04(self):"""用例2"""print('执行用例test_login_04断言1')pytest.assume(3 == 3)print('执行用例test_login_04断言2')pytest.assume(True)
不加任何参数,控制台输出了执行用例所在的文件、用例执行结果(..)、文件百分比
命令行执行:pytest
#test_01.pyif __name__ == '__main__':pytest.main()C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py .. [ 50%]
test_02.py .. [100%]============================== 4 passed in 0.08s ==============================Process finished with exit code 0
-v 说明:控制台可以输出用例更加详细的执行信息,比如用例所在的文件、类、用例名称、用例执行结果(PASSED)、用例百分比等。
命令行执行:pytest -v
#test_01.pyif __name__ == '__main__':pytest.main(['-v'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py::Test::test_login_01 PASSED [ 25%]
test_01.py::Test::test_login_02 PASSED [ 50%]
test_02.py::Test::test_login_03 PASSED [ 75%]
test_02.py::Test::test_login_04 PASSED [100%]============================== 4 passed in 0.08s ==============================Process finished with exit code 0
-k 说明:允许你使用表达式指定希望运行的测试用例,如果某测试用例名是唯一的,或者多个测试用例名的前缀和后缀相同,就可以使用表达式快速定位,如果你想执行的测试用例名字需包含login_01,就可以这么写pytest.main(['-v', '-k', 'login_01]),如果你想执行的测试用例名字需包含login_01和login_03,就可以这没写pytest.main(['-v', '-k', 'login_01 or login_03'])
控制台输出了选择了2个用例,未选择2个用例、通过了2个用例
collected 4 items / 2 deselected / 2 selected
======================= 2 passed, 2 deselected in 0.05s =======================
命令行执行:pytest -k 'login_01 or login_03'
#test_01.pyif __name__ == '__main__':pytest.main(['-v', '-k', 'login_01 or login_03'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 items / 2 deselected / 2 selectedtest_01.py::Test::test_login_01 PASSED [ 50%]
test_02.py::Test::test_login_03 PASSED [100%]======================= 2 passed, 2 deselected in 0.05s =======================Process finished with exit code 0
-m 说明:标记用于测试用例并分组,以便快速选中并运行,以test_login_01()和test_login_02()为例,希望同时选中并执行,需预先做好标记,假设标记名是run,则可使用@pytest.mark.run装饰器来做标记,调用执行用pytest.main(['-v', '-m', 'run'])
命令行执行:pytest -m run
#test_01.py#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):@pytest.mark.rundef test_login_01(self):"""用例1"""print('执行用例test_login_01断言1')pytest.assume(1 == 1)print('执行用例test_login_01断言2')pytest.assume(2 == 2)@pytest.mark.rundef test_login_02(self):"""用例2"""print('执行用例test_login_02断言1')pytest.assume(3 == 3)print('执行用例test_login_02断言2')pytest.assume(True)if __name__ == '__main__':pytest.main(['-v', '-m', 'run'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 items / 2 deselected / 2 selectedtest_01.py::Test::test_login_01 PASSED [ 50%]
test_01.py::Test::test_login_02 PASSED [100%]======================= 2 passed, 2 deselected in 0.07s =======================Process finished with exit code 0
-s 说明:该选项允许测试运行时输出任何符合标准的输出流信息,例如代码里面的print。正常情况下,所有输出都会被捕获,测试失败时,pytest会做出判断并输出失败报告。
命令行执行:pytest -s
#test_01.pyif __name__ == '__main__':pytest.main(['-v', '-s'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py::Test::test_login_01 执行用例test_login_01断言1
执行用例test_login_01断言2
PASSED
test_01.py::Test::test_login_02 执行用例test_login_02断言1
执行用例test_login_02断言2
PASSED
test_02.py::Test::test_login_03 执行用例test_login_03断言1
执行用例test_login_03断言2
PASSED
test_02.py::Test::test_login_04 执行用例test_login_04断言1
执行用例test_login_04断言2
PASSED============================== 4 passed in 0.07s ==============================Process finished with exit code 0
-x 说明:正常情况下,pytest会运行每一个搜索到的测试用例,如果某个测试函数被断言失败,或者触发了外部异常,则该测试用例的运行就会停止,pytest将其标记为失败后会继续运行下一个测试用例。通常这就是我们期望的运行模式,但是在debug时,我们希望遇到失败时立即停止整个会话,这时-x就派上用场了。
命令行执行:pytest -x
#test_01.py#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):def test_login_01(self):"""用例1"""print('执行用例test_login_01断言1')pytest.assume(1 == 0)print('执行用例test_login_01断言2')pytest.assume(2 == 2)def test_login_02(self):"""用例2"""print('执行用例test_login_02断言1')pytest.assume(3 == 3)print('执行用例test_login_02断言2')pytest.assume(True)if __name__ == '__main__':pytest.main(['-v', '-x'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py::Test::test_login_01 FAILED [ 25%]================================== FAILURES ===================================
_____________________________ Test.test_login_01 ______________________________tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = Nonedef reraise(tp, value, tb=None):try:if value is None:value = tp()if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 1 Failed Assumptions:
E
E test_01.py:11: AssumptionFailure
E >> pytest.assume(1 == 0)
E AssertionError: assert FalseC:\Users\admin\AppData\Roaming\Python\Python37\site-packages\six.py:702: FailedAssumption
---------------------------- Captured stdout call -----------------------------
执行用例test_login_01断言1
执行用例test_login_01断言2
=========================== short test summary info ===========================
FAILED test_01.py::Test::test_login_01 - pytest_assume.plugin.FailedAssumption:
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 failed in 0.08s ==============================Process finished with exit code 0
--maxfail=num 说明:假设你允许pytest失败几次后再停止,则可以使用--maxfail选项,明确指定可以失败几次后停止整个会话。
命令行执行:pytest --maxfail=2
#test_01.py#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):def test_login_01(self):"""用例1"""print('执行用例test_login_01断言1')pytest.assume(1 == 0)print('执行用例test_login_01断言2')pytest.assume(2 == 2)def test_login_02(self):"""用例2"""print('执行用例test_login_02断言1')pytest.assume(3 == 3)print('执行用例test_login_02断言2')pytest.assume(True)
test_01.py中有一个断言失败,最大失败次数设置成1 pytest.main(['-v', '--maxfail=1'])和pytest.main(['-v', '-x'])效果一样的,当遇到第一个失败时,就停止整个会话执行
#test_01.pyif __name__ == '__main__':pytest.main(['-v', '--maxfail=1'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py::Test::test_login_01 FAILED [ 25%]================================== FAILURES ===================================
_____________________________ Test.test_login_01 ______________________________tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = Nonedef reraise(tp, value, tb=None):try:if value is None:value = tp()if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 1 Failed Assumptions:
E
E test_01.py:11: AssumptionFailure
E >> pytest.assume(1 == 0)
E AssertionError: assert FalseC:\Users\admin\AppData\Roaming\Python\Python37\site-packages\six.py:702: FailedAssumption
---------------------------- Captured stdout call -----------------------------
执行用例test_login_01断言1
执行用例test_login_01断言2
=========================== short test summary info ===========================
FAILED test_01.py::Test::test_login_01 - pytest_assume.plugin.FailedAssumption:
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 failed in 0.06s ==============================Process finished with exit code 0
test_01.py中有一个断言失败,最大失败次数设置成2 pytest.main(['-v', '--maxfail=2']),当遇到第一个失败时,未满足2个失败的条件,所以会继续执行后续的用例。
#test_01.py#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytestclass Test(object):def test_login_01(self):"""用例1"""print('执行用例test_login_01断言1')pytest.assume(1 == 0)print('执行用例test_login_01断言2')pytest.assume(2 == 2)def test_login_02(self):"""用例2"""print('执行用例test_login_02断言1')pytest.assume(3 == 3)print('执行用例test_login_02断言2')pytest.assume(True)if __name__ == '__main__':pytest.main(['-v', '--maxfail=2'])C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe C:/Users/admin/Desktop/AutoTest/Test/test/test_01/test_01.py
============================= test session starts =============================
platform win32 -- Python 3.7.4, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- C:\Users\admin\AppData\Local\Programs\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\admin\Desktop\AutoTest\Test\test\test_01
plugins: assume-2.2.1, ordering-0.6
collecting ... 收集的测试用例:[<Function test_login_01>, <Function test_login_02>, <Function test_login_03>, <Function test_login_04>]
collected 4 itemstest_01.py::Test::test_login_01 FAILED [ 25%]
test_01.py::Test::test_login_02 PASSED [ 50%]
test_02.py::Test::test_login_03 PASSED [ 75%]
test_02.py::Test::test_login_04 PASSED [100%]================================== FAILURES ===================================
_____________________________ Test.test_login_01 ______________________________tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = Nonedef reraise(tp, value, tb=None):try:if value is None:value = tp()if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 1 Failed Assumptions:
E
E test_01.py:11: AssumptionFailure
E >> pytest.assume(1 == 0)
E AssertionError: assert FalseC:\Users\admin\AppData\Roaming\Python\Python37\site-packages\six.py:702: FailedAssumption
---------------------------- Captured stdout call -----------------------------
执行用例test_login_01断言1
执行用例test_login_01断言2
=========================== short test summary info ===========================
FAILED test_01.py::Test::test_login_01 - pytest_assume.plugin.FailedAssumption:
========================= 1 failed, 3 passed in 0.09s =========================Process finished with exit code 0