2014-08-28 10 views
6

Ich möchte einen Wert von einem Fixture zu mehreren Tests/Testklassen zurückgeben können, aber der Wert, der übergeben wird, ist eine Funktion.pytest fixture gibt immer eine Funktion zurück

Hier ist mein Code:

import pytest 

@pytest.fixture() 
def user_setup(): 
    user = { 
     'name': 'chad', 
     'id': 1 
    } 
    return user 

@pytest.mark.usefixtures('user_setup') 
class TestThings: 
    def test_user(self): 
     assert user_setup['name'] == 'chad' 

Die Ausgabe lautet:

=================================== FAILURES =================================== 
_____________________________ TestThings.test_user _____________________________ 

self = <tests.test_again.TestThings instance at 0x10aed6998> 

    def test_user(self): 
>  assert user_setup['name'] == 'chad' 
E  TypeError: 'function' object has no attribute '__getitem__' 

tests/test_again.py:14: TypeError 
=========================== 1 failed in 0.02 seconds =========================== 

Aber wenn ich meinen Test so umschreiben, dass es nicht die usefixtures Dekorateur nicht verwendet, funktioniert es wie erwartet:

def test_user(user_setup): 
    assert user_setup['name'] == 'chad' 

Irgendwelche Ideen, warum es nicht funktioniert, wenn ich versuche, die Decorator-Methode zu verwenden?

Antwort

13

werden bedeutet zu rufen Wenn Sie die @pytest.mark.usefixtures Marker verwenden Sie immer noch eine ähnlich benannten Eingabeargument zur Verfügung stellen müssen, wenn Sie die Halterung wollen in injiziert werden zu deiner Testfunktion.

Wie in den py.test docs for fixtures beschrieben:

Der Name der Leuchte Funktion später Bezug genommen werden kann seinen Aufruf vor dem Ausführen von Tests ... Testfunktionen direkt zu verursachen Befestigungs Namen als Eingabeargumente verwenden können, in In diesem Fall wird die Fixture-Instanz , die von der Fixture-Funktion zurückgegeben wird, injiziert.

So nur die @pytest.mark.usefixtures Dekorator wird nur die Funktion aufrufen. Wenn Sie ein Eingabeargument angeben, erhalten Sie das Ergebnis dieser Funktion.

Sie müssen nur @pytest.mark.usefixtures verwenden, wenn Sie ein Fixture aufrufen möchten, es aber nicht als Eingabeargument für Ihren Test verwenden möchten. Wie in der py.test docs beschrieben.

Der Grund, warum Sie eine Ausnahme erhalten, die über user_setup spricht, ist eine Funktion, weil innerhalb Ihrer Funktion der Name user_setup tatsächlich auf die Funktion verweist, die Sie zuvor in der Datei definierten. Um den Code zu arbeiten, wie Sie erwarten, man braucht ein Argument für die test_user Funktion hinzuzufügen:

@pytest.mark.usefixtures('user_setup') 
class TestThings: 
    def test_user(self, user_setup): 
     assert user_setup['name'] == 'chad' 

nun aus der Perspektive der test_user Funktion user_setup der Name des Funktionsargument beziehen, die die zurückgegeben werden Wert des Fixtures wie von py.test injiziert.

Aber wirklich brauchen Sie nur nicht die @pytest.mark.usefixtures Dekorateur überhaupt zu verwenden.

+2

Danke für die klare Erklärung, wie es funktioniert. Ich dachte, dass ich dies erreichen könnte, ohne das Argument zu jeder Testfunktion hinzufügen zu müssen, die innerhalb meiner Testklasse liegt. – Cass

+0

Ich suchte gerade nach den Unterschieden und/oder Anwendungsfällen für diese beiden Varianten und wann ich welche verwenden sollte, danke für diese Erklärung. – Zelphir

+0

Laut offizieller Dokumentation sollten Sie 'user_setup' nicht zu jeder Testfunktion hinzufügen, wenn sie unter einer Klasse gruppiert sind, die mit' @ pytest.mark.usefixtures' versehen ist: "Aufgrund des usefixtures marker, cleandir fixture wird für die Ausführung jeder Testmethode benötigt, so als ob Sie für jede von ihnen ein "cleandir" -Funktionsargument angegeben hätten. "(Quelle: http://pytest.org/latest/fixture.html#using-fixtures) -from-classes-modules-or-projects) Schließlich besteht der springende Punkt bei Gruppentests darin, sie als Stapel zu manipulieren.) ... Vielleicht ist das ein pytest-Bug? – Zearin

-1

In beiden Fällen, in der globalen Bereich bezieht sich user_setup auf die Funktion. Der Unterschied besteht darin, dass Sie in Ihrer Nicht-Fixture-Version einen Parameter mit demselben Namen erstellen, der ein klassisches Rezept für Verwirrung ist.

In dieser Nicht-Fixture-Version innerhalb des Bereichs bezieht sich Ihr user_setup Bezeichner auf das, was Sie gerade übergeben, NICHT die Funktion im globalen Gültigkeitsbereich.

Ich glaube, Sie wahrscheinlich user_setup und Indizierung, das Ergebnis wie

assert user_setup()['name'] == 'chad' 
Verwandte Themen