454 Stimmen

Wie kann ich alle Python-Unit-Tests in einem Verzeichnis ausführen?

Ich habe ein Verzeichnis, das meine Python-Unit-Tests enthält. Jedes Unit-Test-Modul hat die Form test_*.py . Ich versuche, eine Datei namens all_test.py die, Sie haben es erraten, alle Dateien in der oben erwähnten Testform ausführt und das Ergebnis zurückgibt. Ich habe bisher zwei Methoden ausprobiert; beide sind fehlgeschlagen. Ich werde die beiden Methoden zeigen und hoffe, dass jemand da draußen weiß, wie man das richtig macht.

Bei meinem ersten tapferen Versuch dachte ich: "Wenn ich einfach alle meine Testmodule in die Datei importiere und diese dann aufrufe unittest.main() Dingsbums, das funktioniert doch, oder?" Nun, es stellte sich heraus, dass ich falsch lag.

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]

if __name__ == "__main__":
     unittest.main()

Das hat nicht funktioniert, das Ergebnis war:

$ python all_test.py 

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Bei meinem zweiten Versuch dachte ich mir, ok, vielleicht versuche ich, diese ganze Testsache auf eine mehr "manuelle" Art und Weise zu machen. Also habe ich versucht, das unten zu tun:

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
[__import__(str) for str in module_strings]
suites = [unittest.TestLoader().loadTestsFromName(str) for str in module_strings]
[testSuite.addTest(suite) for suite in suites]
print testSuite 

result = unittest.TestResult()
testSuite.run(result)
print result

#Ok, at this point I have a result
#How do I display it as the normal unit test command line output?
if __name__ == "__main__":
    unittest.main()

Auch das hat nicht funktioniert, aber es scheint so nahe dran zu sein!

$ python all_test.py 
<unittest.TestSuite tests=[<unittest.TestSuite tests=[<unittest.TestSuite tests=[<test_main.TestMain testMethod=test_respondes_to_get>]>]>]>
<unittest.TestResult run=1 errors=0 failures=0>

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Ich scheine eine Art von Suite zu haben, und ich kann das Ergebnis ausführen. Ich bin etwas besorgt über die Tatsache, dass es heißt, ich hätte nur run=1 scheint das zu sein run=2 aber es ist ein Fortschritt. Aber wie kann ich das Ergebnis an main übergeben und anzeigen? Oder wie bekomme ich es grundsätzlich so hin, dass ich nur diese Datei ausführen kann und dabei alle Unit-Tests in diesem Verzeichnis ausführe?

4voto

Dunes Punkte 34391

Ich verwende PyDev/LiClipse und habe noch nicht wirklich herausgefunden, wie man alle Tests auf einmal von der GUI aus starten kann. (edit: Sie klicken mit der rechten Maustaste auf den Root-Testordner und wählen Run as -> Python unit-test

Dies ist mein derzeitiger Ausweg:

import unittest

def load_tests(loader, tests, pattern):
    return loader.discover('.')

if __name__ == '__main__':
    unittest.main()

Ich habe diesen Code in ein Modul namens all in meinem Testverzeichnis. Wenn ich dieses Modul als Unittest von LiClipse aus ausführe, werden alle Tests ausgeführt. Wenn ich darum bitte, nur bestimmte oder fehlgeschlagene Tests zu wiederholen, werden nur diese Tests ausgeführt. Es stört auch nicht meinen Kommandozeilen-Testrunner (nosetests) - er wird ignoriert.

Möglicherweise müssen Sie die Argumente ändern in discover basierend auf Ihrer Projektkonfiguration.

3voto

Peter Kofler Punkte 9018

Auf der Grundlage der Antwort von Stephen Cagle Ich habe Unterstützung für verschachtelte Testmodule hinzugefügt.

import fnmatch
import os
import unittest

def all_test_modules(root_dir, pattern):
    test_file_names = all_files_in(root_dir, pattern)
    return [path_to_module(str) for str in test_file_names]

def all_files_in(root_dir, pattern):
    matches = []

    for root, dirnames, filenames in os.walk(root_dir):
        for filename in fnmatch.filter(filenames, pattern):
            matches.append(os.path.join(root, filename))

    return matches

def path_to_module(py_file):
    return strip_leading_dots( \
        replace_slash_by_dot(  \
            strip_extension(py_file)))

def strip_extension(py_file):
    return py_file[0:len(py_file) - len('.py')]

def replace_slash_by_dot(str):
    return str.replace('\\', '.').replace('/', '.')

def strip_leading_dots(str):
    while str.startswith('.'):
       str = str[1:len(str)]
    return str

module_names = all_test_modules('.', '*Tests.py')
suites = [unittest.defaultTestLoader.loadTestsFromName(mname) for mname 
    in module_names]

testSuite = unittest.TestSuite(suites)
runner = unittest.TextTestRunner(verbosity=1)
runner.run(testSuite)

Der Code durchsucht alle Unterverzeichnisse von . für *Tests.py Dateien, die dann geladen werden. Es erwartet jede *Tests.py eine einzige Klasse zu enthalten *Tests(unittest.TestCase) die der Reihe nach geladen und nacheinander ausgeführt werden.

Dies funktioniert mit einer beliebig tiefen Verschachtelung von Verzeichnissen/Modulen, aber jedes Verzeichnis dazwischen muss ein leeres __init__.py Datei. Dies ermöglicht es dem Test, die verschachtelten Module zu laden, indem Schrägstriche (oder Backslashes) durch Punkte ersetzt werden (siehe replace_slash_by_dot ).

3voto

Aaron Punkte 51

Ich habe einfach eine Datei discover.py in meinem Basis-Testverzeichnis erstellt und Import-Anweisungen für alles in meinen Unterverzeichnissen hinzugefügt. Dann ist discover in der Lage, alle meine Tests in diesen Verzeichnissen zu finden, indem es discover.py aufruft

python -m unittest discover ./test -p '*.py'

# /test/discover.py
import unittest

from test.package1.mod1 import XYZTest
from test.package1.package2.mod2 import ABCTest
...

if __name__ == "__main__"
    unittest.main()

1voto

Bactisme Punkte 1514

Da die Testentdeckung ein umfassendes Thema zu sein scheint, gibt es einen speziellen Rahmen für die Testentdeckung:

Lesen Sie hier weiter: https://wiki.python.org/moin/PythonTestingToolsTaxonomy

1voto

John Greene Punkte 1882

Dieses BASH-Skript führt das Python-Unittest-Testverzeichnis von JEDEM Ort im Dateisystem aus, unabhängig davon, in welchem Arbeitsverzeichnis Sie sich befinden: Das Arbeitsverzeichnis ist immer dort, wo das test Verzeichnis befindet.

ALLE TESTS, unabhängig $PWD

unittest Python-Modul ist empfindlich für Ihr aktuelles Verzeichnis, es sei denn, Sie teilen ihm mit, wo (mit discover -s Option).

Dies ist nützlich bei einem Aufenthalt in der ./src o ./example Arbeitsverzeichnis und Sie benötigen einen schnellen allgemeinen Einheitstest:

#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

python -m unittest discover -s "$readlink"/test -v

SELECTED TESTS, unabhängig $PWD

Ich nenne diese Dienstprogrammdatei: runone.py und verwenden Sie es wie folgt:

runone.py <test-python-filename-minus-dot-py-fileextension>

#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

(cd "$dirname"/test; python -m unittest $1)

Keine Notwendigkeit für eine test/__init__.py Datei, um Ihre Verpackungs-/Gedächtniskosten während der Produktion zu belasten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X