我们的pytest环境具有许多固定装置(主要是scope='function'
和scope='module'
),它们的形式如下:
@pytest.yield_fixture(scope='function')
def some_fixture():
... some object initialization ...
yield some_object
... teardown ...
我们使用夹具的拆卸阶段(在成品率之后)删除一些专门为测试创建的资源。
但是,如果测试失败,我不希望执行拆卸,因此我们将拥有仍然存在的资源可用于进一步的调试。
例如,这是在我们所有测试框架中都重复出现的常见情况:
@pytest.yield_fixture(scope='function')
def obj_fixture():
obj = SomeObj.create()
yield obj
obj.delete()
def test_obj_some_field(obj_fixture):
assert obj_fixture.some_field is True
在这种情况下,如果assert
中的条件为True
,我希望obj.delete()
执行。
但是,如果测试失败,我希望pytest跳过obj.delete()
和yield
之后的其他内容。
谢谢。
编辑 我希望在不更改固定装置和测试代码的情况下完成该过程,我更喜欢自动过程,而不是在整个测试代码库中进行此重构。
答案 0 :(得分:2)
pytest docs中有一个有关如何执行此操作的示例。基本思想是,您需要在挂钩函数中捕获此信息并将其添加到测试item
中可用的测试request
中,测试request
可以通过{{ 1}}固定装置。
对您来说,看起来像这样:
# conftest.py
import pytest
@pytest.hookimpl(tryfirst = True, hookwrapper = True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
rep = outcome.get_result()
# set a report attribute for each phase of a call, which can
# be "setup", "call", "teardown"
setattr(item, "rep_" + rep.when, rep)
# test_obj.py
import pytest
@pytest.fixture()
def obj(request):
obj = 'obj'
yield obj
# setup succeeded, but the test itself ("call") failed
if request.node.rep_setup.passed and request.node.rep_call.failed:
print(' dont kill obj here')
else:
print(' kill obj here')
def test_obj(obj):
assert obj == 'obj'
assert False # force the test to fail
如果您使用pytest -s
运行此命令(不要让pytest捕获灯具的输出),则会看到类似的输出
foobar.py::test_obj FAILED dont kill obj here
这表明我们正在到达条件的右分支。
答案 1 :(得分:0)
拆卸的目的是与测试通过还是失败无关。
因此,我建议编写您的拆卸代码,使其足够健壮,无论测试通过还是失败都可以执行,或者将清理添加到测试的末尾,以便在没有前面的情况下被调用分类失败,如果之前没有发生异常
答案 2 :(得分:0)
设置一个类级别标志以指示通过/失败,并在拆解中进行检查。这没有经过测试,但是应该可以给您带来启发:
@pytest.yield_fixture(scope='function')
def obj_fixture():
obj = SomeObj.create()
yield obj
if this.passed:
obj.delete()
def test_obj_some_field(obj_fixture):
assert obj_fixture.some_field is True
this.passed = True