2017-04-05 116 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()