Pytest学习笔记
API文档地址:API Reference — pytest documentation
命名规则
- 文件名需以test_开头或者_test结尾
- 类名需以 Test开头
- 方法需以test开头
若不按照命名规则,使用pytest一次性运行多个用例时,不按照命名规则的文件/case将被跳过
运行顺序与运行命令
- 默认执行顺序:文件之间按照ASCII顺序,0~9——>A~Z——>a~z,文件内的用例为从上往下执行
- 使用某些插件可以改变文件执行顺序:pytest-ordering,或者随机pytest-random-ordering
- 退出码:当case运行完成后,控制台打印出运行信息,最终有总结退出码是什么,例如exit code为0
有case失败时,exit code为1,当使用脚本运行完成后,命令行中执行echo $?可以查看对应exit code的执行情况。
Exit code 0
All tests were collected and passed successfully
Exit code 1
Tests were collected and run but some of the tests failed
Exit code 2
Test execution was interrupted by the user(执行时使用Crtl C中断执行)
Exit code 3
Internal error happened while executing tests(脚本中有内部错误)
Exit code 4
pytest command line usage error(执行的命令行参数错误)
Exit code 5
No tests were collected(没有test被执行)
- pytest -x:当第一个用例失败后直接停止;pytest --maxfail=2:当两个用例执行失败后再停止
- pytest还可以指定目录、模块、类、方法,根据名字、标签运行用例
- 指定目录:pytest 目录
- 指定模块:pytest 目录/模块
- 指定类:pytest 目录/模块::类
- 指定方法:pytest 目录/模块::类::方法
- 根据名字:pytest -k 名字
- 不包含xx:pytest -k "not xxx"
- xx与xx:pytest -k "xx and xx"
- xx或xx:pytest -k "xx or xx"
- 根据标签:在方法上添加装饰器:@pytest.mark.webtes(标签名)。执行:pytest -m webtest
- PDB:pytest内置的调试,pytest --pdb命令当test失败时进入PDB调试模式,但需要在控制台输入命令进行调试,建议直接使用断点调试。
- 调用python的命令执行Pytest,pytest.main(['param1','param2','path'])
- pytest -v:输出更详细的用例执行信息,pytest -s:显示程序中的print和log输出,更多命令详细使用可以执行pytest -h查看帮助
断言与异常
- 直接使用assert进行断言,assert 断言表达式,失败message。某些特殊情况的比较:
- 比较长字符串:显示上下文差异
- 比较长序列:第一个失败的索引
- 比较字典:不同的条目
- 使用pytest.raises()可以抛出已知异常。放在函数内,with pytest.raises()
- 使用装饰器@pytest.mark,xfail(raises=异常)来检查异常。
- 使用钩子函数自定义异常:pytest_assertrepr_compare()
fixture
- 某方法加上@pytest.fixture装饰器表示该方法是一个夹具函数。当有方法的参数是该夹具函数时,会实例化夹具函数,并返回夹具函数中的返回值。例:
import pytest
class Fruit:
def __init__(self, name):
self.name = name
self.cubed = False
def cube(self):
self.cubed = True
class FruitSalad:
def __init__(self, *fruit_bowl):
self.fruit = fruit_bowl
self._cube_fruit()
def _cube_fruit(self):
for fruit in self.fruit:
fruit.cube()
# Arrange
@pytest.fixture
def fruit_bowl():
return [Fruit("apple"), Fruit("banana")]
def test_fruit_salad(fruit_bowl):
# Act
fruit_salad = FruitSalad(*fruit_bowl)
# Assert
assert all(fruit.cubed for fruit in fruit_salad.fruit)
fruit_bowl()就是一个fixture,test_fruit_salad()方法中的参数有fruit_bowl(),他会先实例化fruit_bowl(),获取到fixture返回的值后,再执行test_fruit_salad()下面的语句。上述fixtrue使用替换成手动调用如下:
def fruit_bowl():
return [Fruit("apple"), Fruit("banana")]
def test_fruit_salad(fruit_bowl):
# Act
fruit_salad = FruitSalad(*fruit_bowl)
# Assert
assert all(fruit.cubed for fruit in fruit_salad.fruit)
# Arrange
bowl = fruit_bowl() #实例化
test_fruit_salad(fruit_bowl=bowl) #将实例化后的方法当参数传进去
- fixture可以请求其他的fixture
- fixture可以重复使用,不同的方法可以调用同一个fixture,且相互之间互不干扰,每个方法都可以从夹具中获取到自己的结果
- 一个测试方法或者fixture可以一次请求多个fixture,即参数中可以带多个fixture
- 自动夹具:在装饰器中加上autouse=True,表示该fixture即使在方法中未请求,他也会自动帮你的所有测试方法请求该fixture
@pytest.fixture(autouse=True)
def append_first(order, first_entry):
return order.append(first_entry)
- fixture的scope:function,class,module,package,session
function
: the default scope, the fixture is destroyed at the end of the test.class
: the fixture is destroyed during teardown of the last test in the class.module
: the fixture is destroyed during teardown of the last test in the module.package
: the fixture is destroyed during teardown of the last test in the package.session
: the fixture is destroyed at the end of the test session.
MonkeyPatching
- 猴子补丁:属性在运行时被动态替换,只在代码运行时发挥作用,即在内存中,不会修改修改源码,因此只会在当前运行的程序实例中有效。
- 猴子补丁破坏了封装,而且容易导致程序与补丁代码的实现细节紧密耦合,所以被视为临时的变通方案,不是集成代码的推荐方式。
- 主要方法如下:
monkeypatch.setattr(obj, name, value, raising=True) //设置属性
monkeypatch.delattr(obj, name, raising=True) //删除属性
monkeypatch.setitem(mapping, name, value) //设置字典
monkeypatch.delitem(obj, name, raising=True) //删除字典
monkeypatch.setenv(name, value, prepend=False) //设置环境变量
monkeypatch.delenv(name, raising=True) //删除环境变量
monkeypatch.syspath_prepend(path) //修改sys.path
monkeypatch.chdir(path) //更改当前工作路径
参数化
pytest有三种参数化方式:
1.@pytest.fixture,使用fixture的返回值来传参
2.使用@pytest.mark.parametrize 允许在测试函数或类中定义多组参数,在用例中实现参数化
3.使用钩子函数:pytest_generate_tests 允许定义自定义参数化方案或扩展:详细说明文档:pytest文档69-Hook函数之参数化生成测试用例pytest_generate_tests - 上海-悠悠 - 博客园 (cnblogs.com)
@pytest.mark.parametrize("test_input,expected", [("3 5", 8), ("2 4", 6), ("6*9", 42)])
1.表示传入test_input和expected两个参数,值用元组表示,一个元组代表一组值。有三组值,表示该方法会执行三次,每次用不同的值。
2.在@pytest.mark.parametrize中定义的参数,在方法中要传入该形参。
3.@pytest.mark.parametrize中可声明scope作用域,默认为function,表示加载完所有参数后在一个方法上执行。scope还可以取值:class,module,表示每一个参数在执行完当前类或者模块后再替换为下一个参数。
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
两个作用在同一个方法上,表示使用笛卡尔积的方式取参,即x=0/y=2, x=1/y=2, x=0/y=3, and x=1/y=3 这几组值。
SKIP
- pytest可以跳过某些测试方法
- 无条件跳过:@pytest.mark.skip(reason=""),不需要满足任何条件,直接跳过该case,且在控制台使用-rs打印出reason
- 在特定条件下跳过:@pytest.mark.skipif(条件,reason=""),满足条件时,跳过该case,且在控制台使用-rs打印出reason(使用后发现条件中无法引用变量,引用了就会报找不到该变量)
- 当导入的模块缺失的时候跳过:@pytest.importskip("aaa"),当没有import aaa模块时,跳过该case
- pytest还可以跳过class、module和文件、目录
- 当case需要复用某些makers时,可以将maker写在文件中,用一个变量表示,然后直接@该变量即可,跨文件使用时则先导入该变量,再@引用
XFail
pytest可以使一些测试方法在预期中失败
- 无条件失败:@pytest.mark.xfail(reason),装饰在测试方法上,该方法仍会执行但是不会报错,且在控制台会标记该方法为XFail,打印出reason(reason可选)
- 在特定条件下失败:@pytest.mark.xfail(条件,reason=""),满足条件时,该方法会标记为xfail,且在控制台打印出reason
- 抛出指定异常失败:@pytest.mark.xfail(raises=RuntimeError),可以指定单个异常,或者多个异常,多个异常使用元组表示。该方法失败的原因是RuntimeError,如果该方法失败但是raises未声明该异常,则会被当成常规的失败处理
- 将方法标记为xfail,该方法仍会执行;若想把该方法标记为xfail,但不想执行,使用run参数,设置为false即可:@pytest.mark.xfail(run=False)
- 使用参数strict=True,可以将标记为xfail的方法结果变为xpass("unexpectedly passing":出乎意料的通过)
- pytest -runxfail,使用该命令运行,所有方法都会被打上xfail标记,即使该方法没有加xfail标记,但这样@pytest.mark.xfail就会不起作用
Skip/xfail with parametrize
skip和xfail也可以集成在参数中:
pytest.param()也可用于传参
import pytest
@pytest.mark.parametrize(
("n", "expected"),
[
(1, 2),
pytest.param(1, 0, marks=pytest.mark.xfail),
pytest.param(1, 3, marks=pytest.mark.xfail(reason="some bug")),
(2, 3),
(3, 4),
(4, 5),
pytest.param(
10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k")
),
],
)
def test_increment(n, expected):
assert n 1 == expected
pytest-dependency
- 用例依赖插件,使用前需要install pytest-dependency
- 使用场景:当test2依赖于test1时,就可以使用该插件,即当test1失败了,test2就会跳过不执行,当test1执行成功了,test2才会执行
- 使用方法:在被依赖的方法上进行标记:@pytest.mark.dependency(name=''),name一般为test的名称(注:一定要添加name属性,不然依赖方法很容易找不到被依赖的方法),在依赖的方法上进行标记:@pytest.mark.dependency(depends=['被依赖的name']),依赖方法中也可以同时添加name,被其他的方法依赖
- 若执行case时不想真的fail,可以在被依赖方法中使用pytest.xfail()来标记失败
doctest-文档测试
doctest是Python中自带的一个模块玩,为单元测试的一种,doctest 模块会搜索那些看起来像交互式会话的 Python 代码片段,然后尝试执行并验证结果。在pytest中也可以运行doctest,pytest中文件格式为test*.txt的文件将会被默认为doctest运行
- 格式:在需要运行的代码前面加上>>>,期望的结果前不加
# content of test_example.txt
hello this is a doctest //不会执行
>>> x = 3 //执行的代码
>>> x //执行的代码
3 //期望的结果
2.运行命令:①可直接pytest运行.txt文件 ②pytest --doctest-modules 文件名运行指定文件
Unittest
unittest是Python自带的另一种测试框架,在unittest.TestCase中可以使用pytest的某些属性:
- Marks:skip,skipif,xfail
- Auto-use fixtures 即pytest.fixture(autouse=true)
还有三种属性在unittest.TestCase可能可以运行成功,可能无法运行成功:
- Fixtures(除去autouse的fixtures)
- Parametrization
- custom hooks
Nose
nose也是Python的一种测试框架,使用前需要install。和pytest一样都适用于单元测试,但是分别使用Pytest和nose发现:pytest遇到错误会打印出详细的错误信息,而nose不会,只是抛出错误名称
在nose框架中也可以使用Pytest的某些属性,详细看官方文档。
石墨文档链接:石墨文档
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhhkbhae
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
excel打印预览压线压字怎么办
PHP中文网 06-22