Wie liefert man stdin-, Dateien- und Umgebungsvariableneingaben für Python-Komponententests?

Lesezeit: 5 Minuten

So schreiben Sie Tests, bei denen Bedingungen wie die folgenden auftreten:

  1. Benutzereingabe testen.
  2. Testeingabe aus einer Datei gelesen.
  3. Testeingabe aus einer Umgebungsvariablen gelesen.

Es wäre toll, wenn mir jemand zeigen könnte, wie man die oben genannten Szenarien angeht; Es wäre trotzdem großartig, wenn Sie mich auf ein paar Dokumente/Artikel/Blog-Posts hinweisen könnten, die ich lesen könnte.

  • Überprüfen, ob ich Ihre Frage richtig verstehe: Was Sie wissen möchten, ist: Wie kann man testen, ob eine ausführbare Datei/ein Skript bei einigen Eingaben wie stdin/environment-Variablen die erwarteten Ausgaben wie stdout, stderr oder den Exit-Status liefert?

    – Ciro Santilli

    7. Apr. ’13 um 10:18


  • @CiroSantilli新疆改造中心六四事件法轮功 Das brauche ich genau, weißt du wie das geht?

    – John Balvin Arien

    16. November ’18 um 17:11

  • @JohnBalvinArias siehe meine Antwort 🙂 stackoverflow.com/a/15874291/895245

    – Ciro Santilli

    16. November ’18 um 17:13

Wie liefert man stdin Dateien und Umgebungsvariableneingaben fur Python Komponententests
Mark Rushakoff

In allen drei Situationen, die Sie beschrieben haben, müssen Sie besonders viel tun, um sicherzustellen, dass Sie in Ihrem Design lose Kopplungen verwenden.

Tust du Ja wirklich muss Pythons Unit-Tests durchführen raw_input Methode? Der open Methode? os.environ.get? Nein.

Sie müssen Ihr Design so einrichten, dass Sie andere Methoden zum Abrufen dieser Eingabe ersetzen können. Dann werfen Sie während Ihrer Unit-Tests eine Art Stub ein, der nicht wirklich aufruft raw_input oder open.

Ihr normaler Code könnte beispielsweise so aussehen:

import os
def say_hello(input_func):
    name = input_func()
    return "Hello " + name

def prompt_for_name():
    return raw_input("What is your name? ")

print say_hello(prompt_for_name)
# Normally would pass in methods, but lambdas can be used for brevity
print say_hello(lambda: open("a.txt").readline())
print say_hello(lambda: os.environ.get("USER"))

Die Sitzung sieht wie folgt aus:

What is your name? somebody
Hello somebody
Hello [some text]

Hello mark

Dann sieht dein Test so aus:

def test_say_hello():
    output = say_hello(lambda: "test")
    assert(output == "Hello test")

Denken Sie daran, dass Sie die E/A-Funktionen einer Sprache nicht testen müssen (es sei denn, Sie sind derjenige, der die Sprache entwickelt, was eine ganz andere Situation darstellt).

  • +1: Dies macht den Code nicht nur testbarer, sondern auch wiederverwendbarer, da er nicht an eine bestimmte Eingabequelle gebunden ist.

    – Dave Kirby

    11. Apr ’10 um 13:35

  • Es sei denn, Sie haben das oben Genannte nicht unter Ihrer Kontrolle. Die schöne Route ist oft nicht verfügbar.

    – berühmtgarkin

    21. Apr. ’15 um 14:42

  • Wie funktioniert dieser Ansatz mit mehreren Eingaben, die mehreren Variablen zugewiesen sind? Erstellen Sie mehrere input_funcs oder gibt es einen eleganteren Weg?

    – TomKivy

    7. Mai ’16 um 18:26

Wenn Sie daran gebunden sind, raw_input (oder eine andere spezifische Eingabequelle) zu verwenden, bin ich ein großer Befürworter der Scheinbibliothek. Angesichts des Codes, den Mark Rushakoff in seinem Beispiel verwendet hat:

def say_hello():
    name = raw_input("What is your name? ")
    return "Hello " + name

Ihr Testcode könnte Mock verwenden:

import mock

def test_say_hello():
     with mock.patch('__builtin__.raw_input', return_value="dbw"):
         assert say_hello() == 'Hello dbw'

     with mock.patch('__builtin__.raw_input', side_effect=['dbw', 'uki']):
         assert say_hello() == 'Hello dbw'
         assert say_hello() == 'Hello uki'

Diese Behauptungen würden bestanden. Beachten Sie, dass side_effect die Elemente der Liste der Reihe nach zurückgibt. Es kann so viel mehr! Ich würde empfehlen, die Dokumentation zu überprüfen.

  • Beachten Sie für Python 3, dass __builtin__ wurde umbenannt in builtins und raw_input() wurden input(), daher: mock.patch('builtins.input', return_value='dew')

    – geertjanvdk

    11. Februar ’14 um 10:34


  • Mock ist Teil des Kernpythons in Python 3 als from unittest import mock.

    – dbn

    12. Dezember ’16 um 22:24

  • Danke mir gefällt dieser Ansatz (mit der Python 3 Variante) am besten. Außerdem sind Mocks natürlich sehr hilfreich bei der Verwendung von Pytest

    – dämongolem

    22. November 19 um 13:16 Uhr

Wie liefert man stdin Dateien und Umgebungsvariableneingaben fur Python Komponententests
Ciro Santilli

Wenn Sie ohne einen externen Prozess davonkommen können, tun Sie dies.

Es gibt jedoch Situationen, in denen dies kompliziert ist und Sie den Prozess wirklich verwenden möchten, zB wenn Sie die Befehlszeilenschnittstelle einer ausführbaren C-Datei testen möchten.

Benutzereingabe

Benutzen subprocess.Popen wie in:

process = subprocess.Popen(
    command,
    shell  = False,
    stdin  = subprocess.PIPE,
    stdout = subprocess.PIPE,
    stderr = subprocess.PIPE,
    universal_newlines = True
)
stdout, stderr = process.communicate("the user inputnline 2")
exit_status = process.wait()

Es gibt keinen Unterschied zwischen der Annahme von Eingaben von einem Benutzer und der Annahme aus einer Pipe für Eingaben mit Methoden wie raw_input oder sys.stdin.read().

Dateien

  • Erstellen Sie ein temporäres Verzeichnis und erstellen Sie dort die Dateien, die Sie bei Ihrem Test lesen möchten setUp Methoden:

    tdir = tempfile.mkdtemp(
        prefix = 'filetest_', 
    )
    fpath = os.path.join(tdir,'filename')
    fp = open(fpath, 'w')
    fp.write("contents")
    fp.close()
    
  • Führen Sie das Lesen der Datei in den Tests durch.

  • Entfernen Sie anschließend das Temp-Verzeichnis.

    shutil.rmtree(tdir)
    
  • Das Lesen von Dateien ist ziemlich kompliziert, und die meisten Programme können entweder von Dateien oder von STDIN lesen (zB mit fileinput). Wenn Sie also testen möchten, was passiert, wenn ein bestimmter Inhalt eingegeben wird und Ihr Programm STDIN akzeptiert, verwenden Sie einfach Popen um das Programm zu testen.

Umgebungsvariablen

  • Setzen Sie die Umgebungsvariablen mit os.environ["THE_VAR"] = "the_val"
  • Entschärfe sie mit del os.environ["THE_VAR"]
  • os.environ = {'a':'b'} funktioniert nicht
  • Dann ruf an subprocess.Popen. Die Umgebung wird vom aufrufenden Prozess geerbt.

Vorlagencode

Ich habe ein Modul an mein github das testet STDOUT, STDERR und der Ausstiegsstatus angegeben STDIN, Befehlszeilenargumente und Umgebung. Überprüfen Sie auch die Tests für dieses Modul im Verzeichnis “tests”. Dafür muss es viel bessere Module geben, also nimm meine nur zu Lernzwecken.

  • Wie ich verstehe, kann die Eingabe nur einmal eingefügt werden. Was ist, wenn es eine “while-Schleife” gibt, die Eingaben von Benutzern n-mal sammelt?

    – John Balvin Arien

    16. November ’18 um 17:23

  • @JohnBalvinArias Wenn kein Timing erforderlich ist, ist es nicht möglich, Pipes von Benutzereingaben zu unterscheiden. Wenn es ein Timing gibt, sehen Sie sich pexpect an.

    – Ciro Santilli

    16. November ’18 um 18:03

.

203610cookie-checkWie liefert man stdin-, Dateien- und Umgebungsvariableneingaben für Python-Komponententests?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy