一个pytest插件,允许每个测试函数有多个失败。
项目描述
pytest-check
一个pytest插件,允许每个测试函数有多个失败。
通常,测试函数会在第一个失败的 assert
处失败并停止运行。这对于大量的软件测试来说是完全正常的。然而,有时你可能想检查多个事物,并且你真的想了解每个检查的结果,即使其中一个失败了。
pytest-check
允许每个测试函数有多个失败的“检查”,这样你就可以看到出错的整个情况。
安装
从PyPI
$ pip install pytest-check
从conda (conda-forge)
$ conda install -c conda-forge pytest-check
示例
你可能想要多个检查的快速示例
import httpx
from pytest_check import check
def test_httpx_get():
r = httpx.get('https://www.example.org/')
# bail if bad status code
assert r.status_code == 200
# but if we get to here
# then check everything else without stopping
with check:
assert r.is_redirect is False
with check:
assert r.encoding == 'utf-8'
with check:
assert 'Example Domain' in r.text
导入与fixture
上面的示例使用了导入:from pytest_check import check
。
您也可以不导入而将 check
作为fixture获取
def test_httpx_get(check):
r = httpx.get('https://www.example.org/')
...
with check:
assert r.is_redirect == False
...
验证函数
check
也提供了一些常见检查的辅助函数。这些方法不需要在 with check:
块内部。
函数 | 含义 | 注意 |
---|---|---|
equal(a, b, msg="") |
a == b |
|
not_equal(a, b, msg="") |
a != b |
|
is_(a, b, msg="") |
a is b |
|
is_not(a, b, msg="") |
a is not b |
|
is_true(x, msg="") |
bool(x) is True |
|
is_false(x, msg="") |
bool(x) is False |
|
is_none(x, msg="") |
x is None |
|
is_not_none(x, msg="") |
x is not None |
|
is_in(a, b, msg="") |
a in b |
|
is_not_in(a, b, msg="") |
a 不在 b 中 |
|
is_instance(a, b, msg="") |
isinstance(a, b) |
|
is_not_instance(a, b, msg="") |
not isinstance(a, b) |
|
is_nan(x, msg="") |
math.isnan(x) |
math.isnan |
is_not_nan(x, msg="") |
not math.isnan(x) |
math.isnan |
almost_equal(a, b, rel=None, abs=None, msg="") |
a == pytest.approx(b, rel, abs) |
pytest.approx |
not_almost_equal(a, b, rel=None, abs=None, msg="") |
a != pytest.approx(b, rel, abs) |
pytest.approx |
greater(a, b, msg="") |
a > b |
|
greater_equal(a, b, msg="") |
a >= b |
|
less(a, b, msg="") |
a < b |
|
less_equal(a, b, msg="") |
a <= b |
|
between(b, a, c, msg="", ge=False, le=False) |
a < b < c |
|
between_equal(b, a, c, msg="") |
a <= b <= c |
等同于 between(b, a, c, msg, ge=True, le=True) |
raises(expected_exception, *args, **kwargs) |
引发指定的异常 | 类似于 pytest.raises |
fail(msg) |
记录失败 |
注意:这是一个相对常见的逻辑运算符列表。我不太愿意添加太多,因为很容易添加自己的。
httpx 示例可以用辅助函数重写
def test_httpx_get_with_helpers():
r = httpx.get('https://www.example.org/')
assert r.status_code == 200
check.is_false(r.is_redirect)
check.equal(r.encoding, 'utf-8')
check.is_in('Example Domain', r.text)
您使用的是个人喜好。
定义自己的检查函数
使用 @check.check_func
@check.check_func
装饰器允许您将任何包含 assert 语句的测试辅助函数包装成非阻塞 assert 函数。
from pytest_check import check
@check.check_func
def is_four(a):
assert a == 4
def test_all_four():
is_four(1)
is_four(2)
is_four(3)
is_four(4)
使用 check.fail()
使用 @check.check_func
可能是最简单的。然而,它确实在通过的情况下有一些开销,这可能会影响检查的大型循环。
如果您需要一些加速,请使用以下样式,并借助 check.fail()
。
from pytest_check import check
def is_four(a):
__tracebackhide__ = True
if a == 4:
return True
else:
check.fail(f"check {a} == 4")
return False
def test_all_four():
is_four(1)
is_four(2)
is_four(3)
is_four(4)
将 raises 用作上下文管理器
raises
用作上下文管理器,类似于 pytest.raises
。主要区别在于,如果没有引发正确的异常,则不会停止测试方法的执行。
from pytest_check import check
def test_raises():
with check.raises(AssertionError):
x = 3
assert 1 < x < 4
伪堆栈跟踪
使用 check
,测试可以在每个测试中有多处失败。如果我们为每次失败都包含完整的堆栈跟踪,则可能会产生大量的输出。为了使输出更简洁,pytest-check
实现了一个较短的版本,我们称之为伪堆栈跟踪。
例如,考虑这个测试
def test_example():
a = 1
b = 2
c = [2, 4, 6]
check.greater(a, b)
check.less_equal(b, a)
check.is_in(a, c, "Is 1 in the list")
check.is_not_in(b, c, "make sure 2 isn't in list")
这将导致以下结果
=================================== FAILURES ===================================
_________________________________ test_example _________________________________
FAILURE:
assert 1 > 2
test_check.py, line 14, in test_example() -> check.greater(a, b)
FAILURE:
assert 2 <= 1
test_check.py, line 15, in test_example() -> check.less_equal(b, a)
FAILURE: Is 1 in the list
assert 1 in [2, 4, 6]
test_check.py, line 16, in test_example() -> check.is_in(a, c, "Is 1 in the list")
FAILURE: make sure 2 isn't in list
assert 2 not in [2, 4, 6]
test_check.py, line 17, in test_example() -> check.is_not_in(b, c, "make sure 2 isn't in list")
------------------------------------------------------------
Failed Checks: 4
=========================== 1 failed in 0.11 seconds ===========================
红色输出
失败也将是红色,除非您使用 pytests 的 --color=no
关闭它。
无输出
您可以使用 pytests 的 --tb=no
关闭失败报告。
失败时停止(maxfail 行为)
设置 -x
或 --maxfail=1
将导致此插件在第一次失败检查后停止测试。
设置 -maxfail=2
或更大值将关闭此插件中的任何 maxfail 处理,并由 pytest 控制。
换句话说,maxfail
计数是针对测试的,而不是检查。例外情况是 1
,我们希望在第一次失败检查时停止。
any_failures()
使用 any_failures()
来查看是否有任何失败。
一个用例是将检查块的条件设置为在先前的检查集中未失败
from pytest_check import check
def test_with_groups_of_checks():
# always check these
check.equal(1, 1)
check.equal(2, 3)
if not check.any_failures():
# only check these if the above passed
check.equal(1, 2)
check.equal(2, 2)
加速
如果您有很多检查失败,则您的测试可能不会像您希望的那样快速运行。有几个方法可以加速。
-
--check-max-tb=5
- 每个测试只包含前 5 个失败的重构堆栈跟踪(其余不包含)。- 示例显示
5
,但可以使用任何数字。 - pytest-check 使用我称之为伪堆栈跟踪的自定义堆栈跟踪代码。
- 这与正常的 assert 堆栈跟踪相比,在视觉上更短。
- 内部,它使用内省,这可能很慢。
- 允许有限的伪回溯数量可以显著提高效率。
- 默认值为1。
- 如果你想对所有失败进行伪回溯,请设置一个较大的数字,例如:1000。
- 示例显示
-
--check-max-report=10
- 限制每个测试中报告的失败次数。- 示例中显示的是
10
,但可以使用任何数字。 - 测试仍将报告失败的总数。
- 默认值为无限制。
- 示例中显示的是
-
--check-max-fail=20
- 在此许多检查失败后停止测试。- 如果你的测试代码运行缓慢,并且你想提前退出,这将非常有用。
- 默认值为无限制。
-
这些中的任何一个都可以单独使用,也可以组合使用。
-
建议
- 保留默认设置,相当于
--check-max-tb=1
。 - 如果过多的输出令人烦恼,请设置
--check-max-report=10
或某个可接受的数字。
- 保留默认设置,相当于
局部加速
上述标志是全局设置,适用于测试运行中的每个测试。
在本地,您可以按测试设置这些值。
从examples/test_example_speedup_funcs.py
def test_max_tb():
check.set_max_tb(2)
for i in range(1, 11):
check.equal(i, 100)
def test_max_report():
check.set_max_report(5)
for i in range(1, 11):
check.equal(i, 100)
def test_max_fail():
check.set_max_fail(5)
for i in range(1, 11):
check.equal(i, 100)
贡献
非常欢迎贡献。可以使用tox运行测试。测试覆盖率现在是100%。请确保保持100%。如果您有一个很棒的pull request并且需要帮助将覆盖率恢复到100%,请告诉我。
许可协议
根据MIT许可证分发,"pytest-check"是免费和开源软件。
问题
如果您遇到任何问题,请提交问题,并附上详细描述。
变更日志
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。