pytest
pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点:
- 简单灵活,容易上手;
- 支持参数化;
- 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);
- pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等;
- 测试用例的skip和xfail处理;
- 可以很好的和jenkins集成;
安装
- 运行如下命令
pip install -U pytest
- 检查是否安装成功
pytest --version
# This is pytest version 4.5.0, imported from c:\python27\lib\site-packages\pytest.pyc - 查看帮助命令
pytest -h
简单应用
创建一个test_class.py文件,输入以下代码:
def test_add():
x = 3
y = 4
assert x == y, "test failed because x=" + str(x) + " y=" + str(y)
class TestClass(object):
def test_one(self):
x = "this"
assert 'h' in x
def three_test(self):
x = "check"
assert hasattr(x, 'check')
def test_add(self):
x = 3
y = 4
assert x == y, "test failed because x=" + str(x) + " y=" + str(y)
命令行进入到当前文件夹,运行以下命令:
pytest
py.test
python -m pytest
三个命令的作用一样,都是运行当前文件夹下的测试用例;还可以使用pytest.main()
运行测试用例(当前文件夹内创建一个py文件,将该代码放入,直接运行该文件即可,此种方法和上边三种结果一样,只是以非命令行方式运行,还可以传递参数的方式运行: pytest.main(["-v", "-s"])
,pytest.main()
会返回6种结果:
Exit code | 解释 |
---|---|
0 | 所有用例都被收集并且全部通过 |
1 | 所有用例都被收集并且有失败的用例 |
2 | 被用户暂停 |
3 | 发生内部错误 |
4 | pytest 命令行使用错误 |
5 | 没有测试用例 |
你将会得到下边的输出:
在失败的部分你可以看到失败的方法和失败的行的信息
pytest识别测试文件和测试方法
默认下pytest只能识别以test_
开头和_test
结尾的.py
文件,识别以test.
开头的所有方法、类
查看有效无效的文件命名(tips:如果显式的运行testlogin.py
和 logintest.py
还是可以的,pytest testlogin.py
)
test_login.py - valid
login_test.py - valid
testlogin.py -invalid
logintest.py -invalid
查看有效无效的方法命名(tips:即使是显式的运行file1_method1()
和 three_test()
,也是不可以的)
def test_file1_method1(): - valid
def testfile1_method1(): - valid
def file1_method1(): - invalid
def three_test(): - invaild
运行多个测试用例从单个文件和多个文件
如果当前文件夹下有多个文件,test_sample2.py
, test_sample3.py
想要运行所有的测试用例,只需要运行命令:pytest
就可以了
如果运行单个文件,则运行命令: pytest test_sample2.py
运行指定的测试用例
假如我们当前文件夹下有两个文件:
- test_sample1.py
- test_file1_answer1()
- test_file1_answer2()
- test_sample2.py
- test_file2_answer1()
- test_file2_answer2()
test_sample1.py
内容:
def func(x):
return x + 1
def test_file1_answer1():
assert func(3) == 5
def test_file1_answer2():
assert func(5) == 5
test_sample2.py
内容:
def func(x):
return x + 1
def test_file2_answer1():
assert func(4) == 5
def test_file2_answer2():
assert func(6) == 5
-
运行测试用例通过子串匹配
运行所有名字中含有的answer1
的方法:py.test -k answer1 -v
-k 用来匹配名字中包含表达式的方法
-v 增加显示详细信息
你将看到如下结果:
py.test -k method -v
– 将会运行所有的方法(四个)
py.test -k methods -v
– 不会运行任何的方法 -
运行测试用例通过
markers
pytest
允许为测试用例添加属性通过pytest
markers,@pytest.mark
,定义方法:@pytest.mark.<name>
更新代码test_sample1.py
:import pytest def func(x): return x + 1 @pytest.mark.case1 def test_file1_answer1(): assert func(3) == 5 @pytest.mark.case2 def test_file1_answer2(): assert func(5) == 5
更新代码
test_sample2.py
:import pytest def func(x): return x + 1 @pytest.mark.case1 def test_file2_answer1(): assert func(4) == 5 @pytest.mark.case1 def test_file2_answer2(): assert func(6) == 5
运行通过
marked
的用例:py.test -m <name>
-m 标记的名字
py.test -m case1
将会运行test_file2_answer1()
,test_file2_answer2()
,test_file1_answer1()
py.test -m case2
将会运行test_file1_answer2()
参数化测试
参数化测试是用于一些测试流程一样,测试数据不同的测试用例,以此来简化代码。看下面的例子,传入两组测试数据。创建一个test_addtiton.py
,写入以下代码:
import pytest
@pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
def test_add(input1, input2, output):
assert input1+input2 == output,"failed"
运行 pytest -s -v test_addtiton.py
,将得到跑了两个测试用例,结果如下:
Xfail / Skip 测试
总是有一些我们不想运行的测试,在这种场景,我们可以选择Xfail / Skip这些测试。Xfail标记的测试将会执行,但是不会被记入失败或成功中,如果失败了,也不会有任何追踪的信息,使用方法:@pytest.mark.xfail
;Skip 则意味着直接跳过,不会执行,使用方法:@pytest.mark.skip
将test_addtion.py
代码修改如下
import pytest
@pytest.mark.skip
def test_add_1():
assert 100 + 200 == 400, "failed"
@pytest.mark.skip
def test_add_2():
assert 100 + 200 == 300, "failed"
@pytest.mark.xfail
def test_add_3():
assert 15 + 13 == 28, "failed"
@pytest.mark.xfail
def test_add_4():
assert 15 + 13 == 100, "failed"
def test_add_5():
assert 3 + 2 == 5, "failed"
def test_add_6():
assert 3 + 2 == 6, "failed"
说明:
- test_add_1 and test_add_2 直接被跳过.
- test_add_3 and test_add_4 are xfailed. 将被执行xfailed(on test failure) or xpassed(on - test pass) tests. 失败时,没有失败信息.
- test_add_5 and test_add_6 将被执行,test_add_6失败将会有失败的信息
运行pytest -s -v test_addtion.py
,结果如下:
============================= test session starts =============================
platform win32 -- Python 2.7.15, pytest-4.5.0, py-1.8.0, pluggy-0.11.0 -- c:\python27\python.exe
cachedir: .pytest_cache
rootdir: C:\pytest, inifile: pytest.ini
collected 6 items
test_addtion.py::test_add_1 SKIPPED
test_addtion.py::test_add_2 SKIPPED
test_addtion.py::test_add_3 XPASS
test_addtion.py::test_add_4 XFAIL
test_addtion.py::test_add_5 PASSED
test_addtion.py::test_add_6 FAILED
================================== FAILURES ===================================
_________________________________ test_add_6 __________________________________
def test_add_6():
> assert 3 + 2 == 6, "failed"
E AssertionError: failed
E assert 5 == 6
E -5
E +6
test_addtion.py:36: AssertionError
===== 1 failed, 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.14 seconds =====
并行运行测试
当测试用例比较多的时候,将会花费大量的时间来运行测试用例,因此pytest支持并行测试,来减少运行时间。想要并行运行,首先要安装插件pytest-xdist
,运行命令安装:
pip install pytest-xdist
,然后直接运行pytest -n 4
即可,-n <num> 表示运用多核,充分利用资源,上面的命令将会四个去运行测试用例。
生成HTML报告
想要HTML格式的报告首先安装插件:pip install pytest-html
运行命令:py.test -v -s --html=reportName.html
你将会在文件目录下生成reportName.html
,用浏览器打开如下图(后续介绍Allure):
常用的命令参数
命令行 | 解释 |
---|---|
pytest --version | 显示版本信息 |
pytest --fixtures | 显示可用的内置函数 |
pytest -h | --help | 显示参数和配置的帮助信息 |
pytest --lf | --last-failed | 运行上一次运行失败的用例 |
pytest --ff | --failed-first | 先运行上一次失败的用例,然后运行其他的 |
pytest --last-failed --last-failed-no-failures all | 没有失败的默认运行所有的用例 |
pytest --last-failed --last-failed-no-failures none | 没有失败的不运行任何用例并退出 |
pytest --cache-show | 查看缓存内容 |
pytest --cache-clear | 运行前删除所有的缓存(一般不需要运行) |
pytest -x | --exitfirst | 第一次失败后停止 |
pytest --maxfail=2 | 第二(n)次失败后停止 |
pytest test_mod.py | 运行单个文件中的用例 |
pytest testing/ | 运行文件夹下的用例 |
pytest -k "MyClass and not method" | 关键字表达式(文件名、类名、方法名)运行测试用例 (将运行TestMyClass.test_something 不运行TestMyClass.test_method_simple) |
pytest test_mod.py::test_func | 运行模块内特指的方法 |
pytest test_mod.py::TestClass::test_method | 运行模块下类内特指的方法 |
pytest -m slow | marker运行测试用例(运行所有被装饰器标记@pytest.mark.slow 的用例) |
pytest --pyargs pkg.testing | 从包中运行测试用例(这将要导入import pkg.testing ) |
pytest -ra | 运行测试用例(显示测试总的结果信息,输出信息的最后) |
pytest -rp | 运行测试用例(显E示测试通过的结果信息,输出信息的最后) |
pytest -rE | 运行测试用例(显示测试错误的结果信息,输出信息的最后) |
pytest -rs | 运行测试用例(显示测试跳过的结果信息,输出信息的最后),也可以结合使用 -rfs – 显示跳过、失败的 |
pytest -v pytest1.py | -v 用于显示每个测试函数的执行结果 |
pytest -q pytest1.py | -q 只显示整体测试结果 |
pytest -s pytest1.py | -s 用于显示测试函数中print()函数输出 |
pytest --durations=10 | 获得最慢的10个测试持续时间表 |
pytest --junitxml=path | 生成一个结果集xml 文件,可用于Jenkins 持续集成 |
pytest --pastebin=failed | 为每个失败的用例创建一个URL |
参考:
- https://www.guru99.com/pytest-tutorial.html
- https://docs.pytest.org/en/latest/contents.html
- https://docs.pytest.org/en/stable/reference.html#pytest.config.Config
扩展: