Pytest灯具相互干扰 [英] Pytest fixtures interfering with each other

查看:56
本文介绍了Pytest灯具相互干扰的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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:

  1. 不带密码的用户将灯具交给我
  2. 将没有密码的用户更改为具有密码的

然后有意义的是,返回没有密码而创建的用户的灯具继续返回该用户,但是现在已经添加了密码.

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灯具相互干扰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆