2017-09-15 4 views
1

Ich habe ein Python-Skript, das mehrere os.system Aufrufe ausführt. Sich gegen die Reihe von ihnen als eine Liste von Saiten geltend zu machen, wird einfach (und relativ elegant) sein.Was ist der beste Weg, os.system für Komponententest zu verspotten (PyTest)

Was ist nicht so einfach ist das Abfangen (und Blockieren) der tatsächlichen Anrufe. Im Skript in Frage, ich konnte abstrakt os.system im SUT (*) wie folgt:

os_system = None 

def main(): 
    return do_the_thing(os.system) 

def do_the_thing(os_sys): 
    global os_system 
    os_system = os_sys 

    # all other function should use os_system instead of os.system 

Mein Test ruft my_script.do_the_thing() statt my_script.main() natürlich (eine winzige Menge von nicht getesteten Code zu verlassen).

Alternative Option: Ich konnte das SUT unberührt und ersetzen os.system global in der Testmethode verlassen, bevor main() im SUT aufrufen.

Das wirft neue Probleme auf, die eine globale und dauerhafte Veränderung sind. Gut, also würde ich eine try/finally in der gleichen Testmethode verwenden, und das Original vor Verlassen der Testmethode ersetzen. Das würde funktionieren, ob die Testmethode erfolgreich ist oder nicht.

Gibt es eine sichere und elegante Setup/Teardown zentrischen Weg dies für PyTest tun, obwohl?

Zusätzliche Komplikationen: Ich möchte das gleiche für Stdout und Stderr tun. Ja, es ist wirklich ein main() Skript, das ich teste.

  • SUT == System Under Test

Antwort

2

Der Python 3 (> = 3.3) Standardbibliothek ein great tutorial about Mock in der offiziellen Dokumentation hat. Für Python 2 können Sie die rückportierte Bibliothek verwenden: Mock auf PyPi.

Hier ist eine Beispielverwendung. Sagen Sie den Anruf os.system in dieser Funktion verspotten wollen:

import os 


def my_function(src_dir): 
    os.system('ls ' + src_dir) 

Um das zu tun, können Sie die unittest.mock.patch Dekorateur verwenden, wie folgt aus:

import unittest.mock 


@unittest.mock.patch('os.system') 
def test_my_function(os_system): 
    # type: (unittest.mock.Mock) -> None 
    my_function("/path/to/dir") 
    os_system.assert_called_once_with('ls /path/to/dir') 

Diese Testfunktion wird die os.system Ruf- während seine Ausführung. os.system wird am Ende wiederhergestellt.

Dann gibt es mehrere "Assert" -Methode, um die Aufrufe, die Parameter und die Ergebnisse zu überprüfen. Sie können auch prüfen, ob in bestimmten Umgebungen eine Ausnahme ausgelöst wird.

+0

Großartig. Für PyTest und Python2 ist es nur @ mock.patch ('os.system') und ich kann bestätigen, funktioniert ganz gut. –

Verwandte Themen