Python 3.4.1,pytest 2.6.2。
当测试失败时,pytest
将定期报告测试打印到stdout的内容。例如下面的代码:
def method_under_test():
print("Hallo, Welt!")
return 41
def test_result_only():
result = method_under_test()
assert result == 42
当作为python -m pytest myfile.py
执行时,将报告以下内容:
================================== FAILURES ===================================
______________________________ test_result_only _______________________________
def test_result_only():
result = method_under_test()
> assert result == 42
E assert 41 == 42
pytestest.py:9: AssertionError
---------------------------- Captured stdout call -----------------------------
Hallo, Welt!
========================== 1 failed in 0.03 seconds ===========================
这是一个非常好的功能。但是当我使用pytest的内置capsys
fixture时,就像这样:
def test_result_and_stdout(capsys):
result = method_under_test()
out, err = capsys.readouterr()
assert out.startswith("Hello")
assert result == 42
报告不再包含实际产出:
================================== FAILURES ===================================
___________________________ test_result_and_stdout ____________________________
capsys = <_pytest.capture.CaptureFixture object at 0x000000000331FB70>
def test_result_and_stdout(capsys):
result = method_under_test()
out, err = capsys.readouterr()
> assert out.startswith("Hello")
E assert <built-in method startswith of str object at 0x000000000330C3B0>('Hello')
E + where <built-in method startswith of str object at 0x000000000330C3B0> = 'Hallo, Welt!\n'.startswith
pytestest.py:14: AssertionError
========================== 1 failed in 0.03 seconds ===========================
我不确定这种行为是否符合规范; pytest文档中对readouterr
的描述是:“测试功能完成后,将恢复原始流。”
我试着假设capsys
是一个上下文管理器,并在Assert之前调用了capsys.__exit__()
。这将是一个丑陋的解决方案,但至少是一个解决方案,如果它恢复了我的Assert之前的输出。然而,这只产生
AttributeError: 'CaptureFixture' object has no attribute '__exit__'
接下来,我查看了CaptureFixture
类的源代码,发现了一个看起来很有希望的方法close
(它调用了一些pop_outerr_to_orig()
方法),但是在我的测试中调用capsys.close()
也没有帮助,它根本没有明显的效果。
如何让pytest在使用capsys
的测试失败时报告我的输出?
5条答案
按热度按时间gab6jxml1#
您看到了正确的行为,当使用
capsys.readouterr()
时,您正在使用捕获的输出。因此,stdout和stderr的任何输出将不再显示在测试报告中。但是,在此之后创建的任何新输出并且没有使用的输出仍然会被报告,因此您可以通过再次将其写入输出流来获得完整的输出:r6l8ljro2#
从文档来看,行为似乎是正确的:只有在test函数(
test_result_and_stdout
)完成后,输出流才会恢复,而不是在每次readouterr
调用后。我不认为目前capsys除了捕获它们之外还支持重定向到原始流,这似乎是你想要的。我建议在官方仓库中使用create an issue,看看人们有什么要说的。
1qczuiv03#
正如@flub所描述的,当使用capsys时,stdout和stderr的输出会被捕获和使用,这是capsys的预期行为。如果您想在测试错误捕获中看到消息,可以在捕获消息后将它们写回stdout和stderr。
然而,我发现一个常见的模式是作为同一测试的一部分连续运行几个命令,通常是因为一个命令后的状态更改会影响下一个命令的行为。在测试详细输出时,您需要针对测试中特定命令的输出内容进行测试,而不是测试期间运行的整个输出历史。为了隔离单个命令的输出,您需要在调用命令之前和之后捕获stdout/stderr。这样,在为一个独立的命令打印到stdout之前,您可以 * 捕获并丢弃 * 以前的stdout内容。
不幸的是,在捕获消息后将其发送回stdout和stderr并不合适,因为如果您这样做,它们将污染测试中下一个命令的输出。
我的解决方案是创建一个辅助函数
recapsys
,它的作用是捕获并立即返回stdout/stderr的内容(就像@flub描述的那样)。此外,recapsys
接受任意多个以前的捕获作为参数,并在当前捕获之前重新生成这些捕获。这样,您就可以在调用测试命令之前捕获以前的stdout/stderr内容,然后在运行命令之后将它们打印出来。下面给出了
recapsys
的定义和示例用法。(对于recapsys的基于类的实现,请查看我的Python模板存储库中的类方法。)在
test_fn.py
上运行pytest
会产生以下输出:r9f1avp54#
使用“startswith”作为旁白。您也可以使用“in”关键字,例如:
如果你有大量的数据被传递到stdout,这是很好的,你可以使用“in”来检查你的stdout中的不同行。
你也可以Assert传入stderr而不是stdout的内容:
还请注意这一行:
创建到目前为止stdout和stderr的输出的快照,以便您可以Assert该测试所期望的内容。
ih99xse15#
在pytest >= 3中,
capsys
和capsysfd
都有disabled()
方法,可以用来暂时禁用捕获,使之能够输出诊断。(除了更干净,这是唯一对我有效的方法。