2017-04-05 87 views
0

我在Django中使用了Pytest,并发现了这种奇怪的行为。我有两个用户装置,一个是另一个的超集。一切工作如预期,直到我在同一个测试用例中使用两个灯具。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_password不工作,user_without_password最终被同一个对象。有没有办法确保每次都是新对象?这种行为感觉违反直觉。

回答

0

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

而且,如果你读user_with_password夹具这样的:

  1. 给我与用户灯具,而不密码
  2. 更改用户没有密码有密码

然后它有道理,即返回它创建的用户而不使用密码的fixture将继续返回该用户,但现在它添加了一个密码。

如果要解决这个问题,然后创建一个新创建的对象,而不仅仅是一个单一的对象,像一个夹具:

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