如何在断言上调用方法

时间:2017-04-26 05:18:58

标签: python pytest

我试图在断言发生时以及在调用任何清理代码之前捕获尽可能多的信息。 下面是我们大多数现有测试的简化代码:

在我的conftest.py中:

import pytest
from datetime import datetime

def pytest_runtest_makereport(item, call):
    print('%s: pytest_runtest_makereport(%s)' % (datetime.now(), call))

def pytest_exception_interact(node, call, report):
    print('\n%s: pytest_exception_interact' % datetime.now())

在我的测试文件中:

import pytest
from datetime import datetime

@pytest.fixture(scope='function')
def marshall_me():
    print('\n%s: starting test' % datetime.now())
    yield marshall_me
    print('\n%s: ending test' % datetime.now())

class Device(object):
    def __enter__(self):
        print('\n%s: create object' % datetime.now())
        return self

    def __exit__(self, type, value, traceback):
        print('\n%s: clean-up object' % datetime.now())

def test_fails(marshall_me):
    with Device():
        assert False

当我跑步时,我得到:

test_fails.py::test_fails  2017-04-26 17:07:37.447359: starting test
2017-04-26 17:07:37.447453: pytest_runtest_makereport(<CallInfowhen='setup' result: []>) 
2017-04-26 17:07:37.447583: create object
2017-04-26 17:07:37.448397: clean-up object 
2017-04-26 17:07:37.448614: pytest_runtest_makereport(<CallInfowhen='call' exception: assert False>) 
FAILED 
2017-04-26 17:07:37.462267: pytest_exception_interact 
2017-04-26 17:07:37.462353: ending test
2017-04-26 17:07:37.462428: pytest_runtest_makereport(<CallInfo when='teardown' result: []>)

我不能使用pytest_runtest_makereport和pytest_exception_interact,因为它们在清理功能之后被调用,这对我来说收集重要信息已经太晚了。是否有其他类似的函数在实际生成断言时被调用?

1 个答案:

答案 0 :(得分:1)

你有断言声明的替代形式:

assert <cond>, <expr>

这意味着解释器首先评估条件,如果错误,它将评估要用作AssertionError参数的表达式。因此,要在断言失败时调用函数,您可以使用它:

assert condition_to_be_true(), function_to_call_if_not_true()

请注意,function_to_call_if_not_true()的返回值将用作AssertionError的参数。如果那不是你想要的,你将需要做一些技巧来改变表达式的结果 - 你可以使用布尔运算符来做到这一点。无论x是什么,表达式(x and False) or y将评估为y(根据python的短路规则)。

要完成它,你可以这样做:

assert condition_to_be_true(), (function_to_call_if_not_true() 
                  and False) or ARGUMENT_TO_AssertionError

另一种方法是滥用语言,如果你必须(这应该被认为是邪恶的)。由于断言语句相当于在确认条件为false之后提升AssertionError,您可以简单地重新定义它:

class AssertionError(Exception):
    def __init__(self, *args, **kwds):
        Exception(self, *args, **kwds)
        print("Assertion")

assert condition_to_check()

请注意,您需要重新定义AssertionError语句的当前范围内assert的值。