Pytest wohin mit den erwarteten Daten
Test-Funktion, die ich brauche, um die übergabe von Parametern und die Ausgabe entspricht dem erwarteten Ausgang.
Es ist einfache wenn-Funktion die Antwort ist nur eine kleine Palette oder ein einzeiliger string, die definiert werden kann, innerhalb der test-Funktion, aber angenommen, die Funktion, die ich testen ändert eine config-Datei, die kann riesig sein. Oder das sich daraus ergebende array ist etwas 4 Linien lang, wenn ich es definieren explizit. Wo muss ich das speichern, dass so meine tests sauber bleiben und leicht zu pflegen?
Recht wenn jetzt der string", ich lege einfach eine Datei in der Nähe der .py
test und tun open()
es im test:
def test_if_it_works():
with open('expected_asnwer_from_some_function.txt') as res_file:
expected_data = res_file.read()
input_data = ... # Maybe loaded from a file as well
assert expected_data == if_it_works(input_data)
Sehe ich viele Probleme mit einem solchen Ansatz, wie das problem der Aufrechterhaltung dieser Datei up-to-date. Es sieht schlecht aus als gut.
Ich kann die Dinge wahrscheinlich besser, wenn diese in eine Vorrichtung:
@pytest.fixture
def expected_data()
with open('expected_asnwer_from_some_function.txt') as res_file:
expected_data = res_file.read()
return expected_data
@pytest.fixture
def input_data()
return '1,2,3,4'
def test_if_it_works(input_data, expected_data):
assert expected_data == if_it_works(input_data)
Dass nur verschiebt das problem an einen anderen Ort und in der Regel brauche ich, um zu testen, ob die Funktion funktioniert bei leeren input, input mit ein einzelnes Objekt oder mehrere Objekte, also ich müsste eine große Leuchte, inklusive drei Fällen eine oder mehrere VORRICHTUNGEN. In den Ende-code wird ziemlich chaotisch.
Wenn eine Funktion erwartet eine komplizierte Wörterbuch als Eingang oder zurück gibt das Wörterbuch von der gleichen enormen Größe test-code hässlich wird:
@pytest.fixture
def input_data():
# It's just an example
return {['one_value': 3, 'one_value': 3, 'one_value': 3,
'anotherky': 3, 'somedata': 'somestring'],
['login': 3, 'ip_address': 32, 'value': 53,
'one_value': 3], ['one_vae': 3, 'password': 13, 'lue': 3]}
Es ist ziemlich schwer zu Lesen tests mit solchen VORRICHTUNGEN und halten Sie up-to-date.
Update
Suche nach einer Weile fand ich eine Bibliothek, die gelöst ein Teil ein problem, wenn statt des großen config-Dateien hatte ich große HTML-Antworten. Es ist betamax.
Zur einfacheren Verwendung erstellt habe ich eine Leuchte:
from betamax import Betamax
@pytest.fixture
def session(request):
session = requests.Session()
recorder = Betamax(session)
recorder.use_cassette(os.path.join(os.path.dirname(__file__), 'fixtures', request.function.__name__)
recorder.start()
request.addfinalizer(recorder.stop)
return session
So, jetzt in meinen tests benutze ich nur die session
Vorrichtung, und jede Anfrage, die ich mache, die serialisiert werden automatisch auf die fixtures/test_name.json
- Datei, damit ich das nächste mal den test auszuführen, anstatt eine echte HTTP-request-Bibliothek lädt Sie aus dem Dateisystem:
def test_if_response_is_ok(session):
r = session.get("http://google.com")
Es ist ganz praktisch, weil um diese Geräte up-to-date, ich brauche nur zum reinigen der fixtures
Ordner und führen Sie erneut meinen tests.
- Sehen Sie es aus Sicht der Entwickler, wer hat ein TC-Fehler und muss um zu Debuggen. Er hat einen Namen der Testfälle, so geht er in die Funktion mit diesem Namen. Wenn Sie halten die zu erwartenden Daten getrennt, werden Sie ihn zu zwingen, springen hin und her, um es zu vergleichen. Wann immer Sie können, halten Sie test-Eingang und erwartet Eingaben innerhalb eines Testfalls oder so nahe wie möglich, IMHO.
- also, was ist Ihr Vorschlag? Halten Sie große Brocken von Daten in den Körper der test-Funktion? Was, wenn die binary zum Beispiel?..
- binäre nicht Lesen, na ja, so ist es eine andere Geschichte. Ich sage nur, dass in Prüfungen Aufbewahrung der Nähe verwenden, ist mindestens so viel wichtiger als TROCKEN. Es hängt alles von dem Fall. Sicher, ich schlage vor, Sie Rücken deine Daten... diese
return
du geschrieben hast ist wirklich hässlich und schwer zu verstehen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich hatte ein ähnliches problem einmal, wo ich die zum testen der Konfiguration-Datei gegen eine erwartete Datei. Das ist, wie ich es behoben:
Erstellen Sie einen Ordner mit dem gleichen Namen von Ihrem test-Modul und an der gleichen Stelle. Alle erwarteten Dateien in diesem Ordner.
Erstellen eines Spielplans verantwortlich für das verschieben der Inhalt dieses Ordners in eine temporäre Datei. Ich habe von
tmpdir
Vorrichtung für diese Sache.Verwenden Sie Ihre neue Leuchte.
Denken Sie daran:
datadir
ist genau das gleiche wietmpdir
Vorrichtung, sowie die Möglichkeit der Zusammenarbeit mit Ihrem erwarteten Dateien in den einen Ordner mit dem Namen test-Modul.datadir
Leuchte. Dann können Sie Gebrauch machen von diesen Informationen, die als input oder Vergleich von Daten.dir_util.copy_tree(test_dir, str(tmpdir))
ist erforderlich, um diese Arbeit zu machen.Wenn Sie nur ein paar tests, dann warum nicht die Daten als string-literal:
Wenn Sie eine Handvoll, oder die erwarteten Daten ist wirklich lang, ich denke, Ihrer Nutzung der Geräte, die Sinn macht.
Jedoch, wenn Sie viele haben, dann vielleicht eine andere Lösung besser wäre. In der Tat, für ein Projekt habe ich über hundert input und erwarteten output-Dateien. So baute ich meinen eigenen Test-Frameworks (mehr oder weniger). Ich benutzte Nase, aber PyTest würde auch funktionieren. Ich erstellte eine test-generator, ging das Verzeichnis von test-Dateien. Für jede Eingabe-Datei, wurde ein test ergab, die im Vergleich die aktuelle Ausgabe mit der erwarteten Ausgabe (PyTest nennt es diese parametrisieren). Dann dokumentierte ich meine Rahmen, damit andere es verwenden können. Zu überprüfen und/oder Bearbeiten Sie die tests, die Sie nur Bearbeiten die Eingangs-und/oder erwarteten output-Dateien und nie brauchen, um sich an die python-test-Datei. Zum aktivieren der verschiedenen input-Dateien, um zu haben, verschiedene Optionen definiert, die ich auch crated eine YAML config-Datei für jedes Verzeichnis (JSON funktionieren würde, wie gut zu halten, die Abhängigkeiten nach unten). Die YAML-Daten bestehen aus einem Wörterbuch, wo jeder Schlüssel ist der name der input-Datei und der Wert ist ein dictionary von keywords, die Sie erhalten, an die Funktion übergeben wird getestet, zusammen mit der Eingabe-Datei. Wenn Sie interessiert sind, hier ist die source code und Dokumentation. Ich habe vor kurzem mit dem Gedanken gespielt, definieren Sie die Optionen wie Unittests hier (erfordert nur die eingebaute unittest-lib), aber ich bin mir nicht sicher, ob ich es mag.
subprocess
gibt ein Ergebnis zurück, das ich verwenden möchten, enthält es spezielle Symbole, die verschwinden, wenn ich einfach kopieren-einfügen als string-literal. Ich werde einen Blick auf Ihren code. Danke. Leider, das aussieht wie ein Rad neu erfindet. Wie niemand hatte das gleiche Problem vor.\t
auf den string hin und her und schließlich nur serialisierte Ausgabe-string. Dies könnte auch schlimm, wenn Daten Typ binary oder hat eine komische Codierung.Denke, wenn Sie den gesamten Inhalt der config-Datei wirklich getestet werden muss.
Wenn nur mehrere Werte oder Zeichenketten überprüft werden muss, bereiten Sie eine zu erwartende Vorlage für die config. Die getesteten Orten, die markiert werden als "Variablen" mit einer speziellen syntax. Dann bereiten Sie eine separate erwartete Liste der Werte für die Variablen in der Vorlage. Das erwartet, dass die Liste gespeichert werden kann als separate Datei oder direkt im Quellcode.
Beispiel für die Vorlage:
Hier, die template-Variablen werden innerhalb von geschweiften Klammern.
Den erwarteten Werten Aussehen kann:
oder auch als einfache Komma-separierte Liste:
Dann Ihre Prüfung code produzieren kann, der erwarteten Datei aus der Vorlage durch das ersetzen der Variablen mit den erwarteten Werten. Und die erwartete Datei ist verglichen mit dem tatsächlichen.
Aufrechterhaltung der Vorlage und die erwarteten Werte getrennt hat und Vorteil, dass man viele Test-Daten-sets mit der gleichen Vorlage.
Tests nur Variablen
Ein noch besserer Ansatz ist, dass die config-generation-Methode liefert nur die benötigten Werte für die config-Datei. Diese Werte können leicht eingefügt werden in der Vorlage durch eine andere Methode. Aber der Vorteil ist, dass der Test-code kann direkt vergleichen, alle config-Variablen getrennt und in klaren Art und Weise.
Vorlagen
Zwar ist es leicht zu ersetzen Sie die Variablen mit den benötigten Werten in der Vorlage gibt es fertige template-Bibliotheken, die es erlauben, es zu tun, nur in einer Zeile. Hier sind nur ein paar Beispiele: Django, Jinja, Mako
combine_chunks
- Funktion oder wenn ich versuche, es zu testen werde ich Probleme haben wie ich jetzt - wo speichern der endgültigen Konfiguration, wie es zu laden, etc. Ich weiß nicht, wie zu brechen, die die generation in 2 Teile auf, wenn eine Funktion führt eine regex-Suche nach einer Zeile in der Datei aus und hängt etwas.