PyTest 跳过 module_teardown()
PyTest skip module_teardown()
我的测试模块中有以下代码
def teardown_module():
clean_database()
def test1(): pass
def test2(): assert 0
并且我希望 teardown_module()
(一些清理代码)仅在某些测试失败时被调用。否则(如果全部通过)不必调用此代码。
我可以用 PyTest 做这样的把戏吗?
可以。但这有点像黑客。
如此处所写:http://pytest.org/latest/example/simple.html#making-test-result-information-available-in-fixtures
您执行以下操作,以设置用于保存测试调用每个阶段状态的属性:
# content of conftest.py
import pytest
@pytest.mark.tryfirst
def pytest_runtest_makereport(item, call, __multicall__):
rep = __multicall__.execute()
setattr(item, "rep_" + rep.when, rep)
return rep
并且在夹具中,您只需像这样检查这些属性的条件:
import pytest
@pytest.yield_fixture(scope="module", autouse=True)
def myfixture(request):
print "SETUP"
yield
# probably should not use "_collected" to iterate over test functions
if any(call.rep_call.outcome != "passed" for call in request.node._collected):
print "TEARDOWN"
这样,如果与该模块夹具关联的任何测试不是 "passed"(因此 "failed" 或 "skipped"),则条件成立。
此处发布的答案和 link 文档很有帮助,但不足以满足我的需求。如果该模块 (.py) 文件中的任何测试失败,我需要一个模块拆卸函数来独立执行每个模块。
上提供了完整的示例项目
首先,我们需要一个钩子来将测试函数结果附加到
测试节点。这直接取自 pytest 文档:
# in conftest.py
@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"
var_name = "rep_" + rep.when
setattr(item, var_name, rep)
之后,我们需要另一个钩子来让测试用例找到模块和
把自己存储在那里,这样模块就可以很容易地找到它的测试用例。也许
有更好的方法,但我找不到。
# also in conftest.py
@pytest.fixture(scope="function", autouse=True)
def _testcase_exit(request):
yield
parent = request.node.parent
while not isinstance(parent, pytest.Module):
parent = parent.parent
try:
parent.test_nodes.append(request.node)
except AttributeError:
parent.test_nodes = [request.node]
一旦我们这样做了,最好有一个装饰函数来打开模块
完成查看其测试节点,查找是否有任何故障,以及
然后如果有调用与装饰器关联的函数:
# also also in conftest.py
def module_error_teardown(f):
@wraps(f)
@pytest.fixture(scope="module", autouse=True)
def wrapped(request, *args, **kwargs):
yield
try:
test_nodes = request.node.test_nodes
except AttributeError:
test_nodes = []
something_failed = False
for x in test_nodes:
try:
something_failed |= x.rep_setup.failed
something_failed |= x.rep_call.failed
something_failed |= x.rep_teardown.failed
except AttributeError:
pass
if something_failed:
f(*args, **kwargs)
return wrapped
现在我们拥有了所有必要的框架。现在,一个失败的测试用例的测试文件很容易写:
from conftest import module_error_teardown
def test_something_that_fails():
assert False, "Yes, it failed."
def test_something_else_that_fails():
assert False, "It failed again."
@module_error_teardown
def _this_gets_called_at_the_end_if_any_test_in_this_file_fails():
print('')
print("Here's where we would do module-level cleanup!")
我的测试模块中有以下代码
def teardown_module():
clean_database()
def test1(): pass
def test2(): assert 0
并且我希望 teardown_module()
(一些清理代码)仅在某些测试失败时被调用。否则(如果全部通过)不必调用此代码。
我可以用 PyTest 做这样的把戏吗?
可以。但这有点像黑客。 如此处所写:http://pytest.org/latest/example/simple.html#making-test-result-information-available-in-fixtures 您执行以下操作,以设置用于保存测试调用每个阶段状态的属性:
# content of conftest.py
import pytest
@pytest.mark.tryfirst
def pytest_runtest_makereport(item, call, __multicall__):
rep = __multicall__.execute()
setattr(item, "rep_" + rep.when, rep)
return rep
并且在夹具中,您只需像这样检查这些属性的条件:
import pytest
@pytest.yield_fixture(scope="module", autouse=True)
def myfixture(request):
print "SETUP"
yield
# probably should not use "_collected" to iterate over test functions
if any(call.rep_call.outcome != "passed" for call in request.node._collected):
print "TEARDOWN"
这样,如果与该模块夹具关联的任何测试不是 "passed"(因此 "failed" 或 "skipped"),则条件成立。
此处发布的答案和 link 文档很有帮助,但不足以满足我的需求。如果该模块 (.py) 文件中的任何测试失败,我需要一个模块拆卸函数来独立执行每个模块。
上提供了完整的示例项目首先,我们需要一个钩子来将测试函数结果附加到 测试节点。这直接取自 pytest 文档:
# in conftest.py
@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"
var_name = "rep_" + rep.when
setattr(item, var_name, rep)
之后,我们需要另一个钩子来让测试用例找到模块和 把自己存储在那里,这样模块就可以很容易地找到它的测试用例。也许 有更好的方法,但我找不到。
# also in conftest.py
@pytest.fixture(scope="function", autouse=True)
def _testcase_exit(request):
yield
parent = request.node.parent
while not isinstance(parent, pytest.Module):
parent = parent.parent
try:
parent.test_nodes.append(request.node)
except AttributeError:
parent.test_nodes = [request.node]
一旦我们这样做了,最好有一个装饰函数来打开模块 完成查看其测试节点,查找是否有任何故障,以及 然后如果有调用与装饰器关联的函数:
# also also in conftest.py
def module_error_teardown(f):
@wraps(f)
@pytest.fixture(scope="module", autouse=True)
def wrapped(request, *args, **kwargs):
yield
try:
test_nodes = request.node.test_nodes
except AttributeError:
test_nodes = []
something_failed = False
for x in test_nodes:
try:
something_failed |= x.rep_setup.failed
something_failed |= x.rep_call.failed
something_failed |= x.rep_teardown.failed
except AttributeError:
pass
if something_failed:
f(*args, **kwargs)
return wrapped
现在我们拥有了所有必要的框架。现在,一个失败的测试用例的测试文件很容易写:
from conftest import module_error_teardown
def test_something_that_fails():
assert False, "Yes, it failed."
def test_something_else_that_fails():
assert False, "It failed again."
@module_error_teardown
def _this_gets_called_at_the_end_if_any_test_in_this_file_fails():
print('')
print("Here's where we would do module-level cleanup!")