Pytest灯具相互干扰

时间:2017-04-05 09:17:09

标签: django pytest

我正在和Django一起使用Pytest并且遇到了这种奇怪的行为。我有两个用户设备,一个是另一个的超集。一切都按预期工作,直到我在同一测试用例中使用两个灯具。

灯具:

@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_passworduser_without_password最终成为同一个对象。有没有办法确保每次都是新对象?这种行为感觉违反直觉。

1 个答案:

答案 0 :(得分:1)

pytest灯具被设计为高效 - 即如果多次请求灯具,则仅创建一次。这意味着您始终可以从另一个夹具请求夹具,并确保您使用与测试相同的对象。

此外,如果您按照以下方式阅读user_with_password灯具:

  1. 向用户提供没有密码的用户
  2. 更改没有密码的用户以获取密码
  3. 然后有意义的是,返回没有密码创建的用户的夹具继续返回该用户,但现在已经添加了密码。

    如果你想解决这个问题,那么创建一个创建新对象的工具,而不仅仅是一个对象,如:

    @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()