拆卸后 Pytest 断言夹具
Pytest asserting fixture after teardown
我有一个测试,可以制作一个东西,验证它,删除它并确认它已被删除。
def test_thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
assert thing.exists
thing.delete() # Simplified, it also takes a few lines to delete it
assert thing.deleted
接下来我想做更多的测试都使用这个东西,所以下一步很自然地将这个东西 creation/deletion 移动到一个夹具中
@pytest.fixture
def thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
yield thing
thing.delete() # Simplified, it also takes a few lines to delete it
def test_thing(thing):
assert thing.exists
def test_thing_again(thing):
# Do more stuff with thing
...
但现在我失去了我的assert thing.deleted
。
我觉得这里有一些选择,但 none 令人满意。
- 我可以在 fixture 中断言,但据我所知,在 fixture 中放置断言是不好的做法,因为如果它失败,它将导致
ERROR
而不是 FAIL
。
- 我可以保留我的原始测试并创建夹具,但这会导致 creating/deleting 这个东西有很多重复的代码。
- 我无法直接调用夹具,因为我得到了一个
Fixture called directly
异常,所以我可以将事物创建移到夹具和测试都使用的生成器中。不过这感觉很笨拙,如果我的 thing
灯具需要使用另一个灯具会怎样?
我最好的选择是什么?有什么我没有想到的吗?
如果你想测试一个“东西”是否被删除,制作一个没有拆解的夹具,在测试中删除它,然后断言它是否被删除。
@pytest.fixture
def thing_create():
# Perform all the creation steps
thing = Thing()
...
yield thing
def thing_delete(thing):
# Perform all the deletion steps
...
thing.delete()
@pytest.fixture
def thing_all(thing_create):
yield thing_create
thing_delete(thing_create)
def test_thing(thing_all):
assert thing_all.exists
def test_thing_again(thing_create):
thing_delete(thing_create)
assert thing_create.deleted
在适当的地方(以减少重复)而不是在你的逻辑只存在一次的地方使用 fixture 如何?
@pytest.fixture
def thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
yield thing
thing.delete() # Simplified, it also takes a few lines to delete it
def test_thing(thing):
assert thing.exists
def test_thing_does_a_thing(thing):
expected = "expected"
assert thing.do_thing() == expected
def test_thing_deletes():
# just don't use the fixture here
thing = Thing()
thing.delete()
assert thing.deleted
另一种解决方案可能是拥有一个产生上下文管理器的固定装置,这样测试就可以完全控制调用它。
@pytest.fixture
def gen_thing():
@contextmanager
def cm():
thing = Thing() # Simplified, it actually takes many lines to make a thing
try:
yield thing
finally:
thing.delete() # Simplified, it also takes a few lines to delete it
yield cm
def test_thing(gen_thing):
with gen_thing() as thing:
assert thing.exists
assert thing.deleted
def test_thing_again(gen_thing):
with gen_thing() as thing:
# Do more stuff with thing
将上下文管理器创建为闭包意味着它也将具有与固定装置相同的作用域。
我有一个测试,可以制作一个东西,验证它,删除它并确认它已被删除。
def test_thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
assert thing.exists
thing.delete() # Simplified, it also takes a few lines to delete it
assert thing.deleted
接下来我想做更多的测试都使用这个东西,所以下一步很自然地将这个东西 creation/deletion 移动到一个夹具中
@pytest.fixture
def thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
yield thing
thing.delete() # Simplified, it also takes a few lines to delete it
def test_thing(thing):
assert thing.exists
def test_thing_again(thing):
# Do more stuff with thing
...
但现在我失去了我的assert thing.deleted
。
我觉得这里有一些选择,但 none 令人满意。
- 我可以在 fixture 中断言,但据我所知,在 fixture 中放置断言是不好的做法,因为如果它失败,它将导致
ERROR
而不是FAIL
。 - 我可以保留我的原始测试并创建夹具,但这会导致 creating/deleting 这个东西有很多重复的代码。
- 我无法直接调用夹具,因为我得到了一个
Fixture called directly
异常,所以我可以将事物创建移到夹具和测试都使用的生成器中。不过这感觉很笨拙,如果我的thing
灯具需要使用另一个灯具会怎样?
我最好的选择是什么?有什么我没有想到的吗?
如果你想测试一个“东西”是否被删除,制作一个没有拆解的夹具,在测试中删除它,然后断言它是否被删除。
@pytest.fixture
def thing_create():
# Perform all the creation steps
thing = Thing()
...
yield thing
def thing_delete(thing):
# Perform all the deletion steps
...
thing.delete()
@pytest.fixture
def thing_all(thing_create):
yield thing_create
thing_delete(thing_create)
def test_thing(thing_all):
assert thing_all.exists
def test_thing_again(thing_create):
thing_delete(thing_create)
assert thing_create.deleted
在适当的地方(以减少重复)而不是在你的逻辑只存在一次的地方使用 fixture 如何?
@pytest.fixture
def thing():
thing = Thing() # Simplified, it actually takes many lines to make a thing
yield thing
thing.delete() # Simplified, it also takes a few lines to delete it
def test_thing(thing):
assert thing.exists
def test_thing_does_a_thing(thing):
expected = "expected"
assert thing.do_thing() == expected
def test_thing_deletes():
# just don't use the fixture here
thing = Thing()
thing.delete()
assert thing.deleted
另一种解决方案可能是拥有一个产生上下文管理器的固定装置,这样测试就可以完全控制调用它。
@pytest.fixture
def gen_thing():
@contextmanager
def cm():
thing = Thing() # Simplified, it actually takes many lines to make a thing
try:
yield thing
finally:
thing.delete() # Simplified, it also takes a few lines to delete it
yield cm
def test_thing(gen_thing):
with gen_thing() as thing:
assert thing.exists
assert thing.deleted
def test_thing_again(gen_thing):
with gen_thing() as thing:
# Do more stuff with thing
将上下文管理器创建为闭包意味着它也将具有与固定装置相同的作用域。