问题描述
我在Django上使用Pytest,并遇到了这种奇怪的行为.我有两个用户装置,一个是另一个的超集.一切正常,直到我在同一测试用例中使用两个夹具为止.
I am using Pytest with Django and came to this weird behaviour. I have two user fixtures, one being a superset of the other. Everything works as expected until I use both fixtures in the same test case.
固定装置:
@pytest.fixture
def user_without_password():
return User.objects.create_user(username=fake.name(), email=fake.email())
@pytest.fixture
def user_with_password(user_without_password):
user = user_without_password
user.set_password('topsecret')
user.save()
return user
测试
@pytest.mark.django_db()
def test_without_pass(user_without_password):
assert not user_without_password.has_usable_password()
@pytest.mark.django_db()
def test_with_pass(user_with_password):
assert user_with_password.has_usable_password()
# THIS FAILS!!
@pytest.mark.django_db()
def test_both(user_with_password, user_without_password):
assert not user_without_password.has_usable_password()
assert user_with_password.has_usable_password()
最后一个测试无效,因为显然 user_with_password
和 user_without_password
最终是同一对象.有没有办法确保它们每次都是新对象?这种行为感觉违反直觉.
The last test doesn't work since apparently user_with_password
and user_without_password
end up being the same object. Is there a way to ensure that they are new objects each time? This behavior feels counter-intuitive.
推荐答案
pytest固定装置的设计效率很高-即,如果多次请求固定装置,则只会创建一次.这意味着您始终可以从另一个固定装置请求固定装置,并确保您使用与测试相同的对象.
pytest fixtures are designed to be efficient – i.e. if a fixture is requested multiple times it is only created once. That means you can always request a fixture from another fixture and be sure you're using the same object as the test.
此外,如果您像这样阅读 user_with_password
固定装置,则:
Further, if you read your user_with_password
fixture like this:
- 不带密码的用户将灯具交给我
- 将没有密码的用户更改为具有密码的
然后有意义的是,返回没有密码而创建的用户的灯具继续返回该用户,但是现在已经添加了密码.
Then it makes sense that the fixture which returns the user it created without a password continues to return that user, but now it's had a password added.
如果您想解决这个问题,那么创建一个夹具,它可以创建新的对象,而不仅仅是一个对象,例如:
If you want to get around this, then create a fixture that creates new objects rather than just a single object, something like:
@pytest.fixture
def user_without_password_factory():
def create_user_without_password():
return User.objects.create_user(username=fake.name(), email=fake.email())
return create_user_without_password
@pytest.fixture
def user_with_password_factory():
def create_user_with_password():
user = User.objects.create_user(username=fake.name(), email=fake.email())
user.set_password('topsecret')
user.save()
return user
return create_user_with_password
@pytest.mark.django_db()
def test_without_pass(user_without_password_factory):
assert not user_without_password_factory().has_usable_password()
@pytest.mark.django_db()
def test_with_pass(user_with_password_factory):
assert user_with_password_factory().has_usable_password()
# Succeeds!!
@pytest.mark.django_db()
def test_both(user_with_password_factory, user_without_password_factory):
assert not user_without_password_factory().has_usable_password()
assert user_with_password_factory().has_usable_password()
这篇关于Pytest灯具相互干扰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!