Frage

ich eine Testdatei haben, die sehr viel Zeit nehmen, Tests enthält (sie Berechnungen zu einem Cluster senden und auf das Ergebnis warten). Alle diese sind in bestimmten Testcase-Klasse.

Da sie Zeit in Anspruch nehmen und darüber hinaus sind nicht wahrscheinlich zu brechen, würde ich mag in der Lage sein zu entscheiden, ob diese Teilmenge von Tests tut oder nicht ausgeführt (der beste Weg, mit einer Befehlszeilenargument wäre, das heißt " ./tests.py --offline“oder so ähnlich), so konnte ich die meisten Tests oft und schnell und das ganze set ab und laufen, wenn ich Zeit habe.

Für jetzt, ich habe gerade unittest.main() verwenden, um die Tests zu starten.

Danke.

War es hilfreich?

Lösung

Der Standard unittest.main() verwendet den Standard-Test-Loader eine Testsuite aus dem Modul zu machen, in der Haupt ausgeführt wird.

Sie müssen nicht dieses Standardverhalten verwenden.

Sie können zum Beispiel machen drei unittest.TestSuite Instanzen .

  1. Die "schnelle" Teilmenge.

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. Die "langsame" Teilmenge.

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. Die "ganze" gesetzt.

    alltests = unittest.TestSuite([fast, slow])
    

Beachten Sie, dass ich die Testcase Namen angepasst haben schnell gegen langsam anzuzeigen. Sie können Unterklasse unittest.TestLoader die Namen von Klassen zu analysieren und mehrere Lader erstellen.

Dann wird Ihr Hauptprogramm kann Befehlszeilenargumente mit optparse oder argparse (verfügbar seit 2.7 oder 3.2) zu holen, die Suite, die Sie ausführen möchten, schnell, langsam oder alle.

Alternativ können Sie darauf vertrauen, dass sys.argv[1] einen von drei Werten ist und verwenden Sie etwas so Einfaches wie das

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Andere Tipps

Um nur einen einzigen spezifischen Test ausführen können Sie:

$ python -m unittest test_module.TestClass.test_method

Weitere Informationen hier

Eigentlich kann man die Namen des Testfalls als sys.argv passiert und nur diese Fälle geprüft werden.

Zum Beispiel: Angenommen, Sie haben

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

Sie können anrufen

python test.py account

nur Konto Tests haben oder sogar

$ python test.py account customer

haben beide Fälle getestet

Ich tue dies eine einfache skipIf mit:

import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

So kann ich nur einen bereits bestehenden Testfall mit dieser einzigen Linie dekorieren muß (keine Notwendigkeit, Test-Suiten oder ähnlich zu erstellen, nur dass man os.getenv() Ruflinie am Anfang meiner Unit-Test-Datei), und als Standard dieses Test wird übersprungen.

Wenn ich es, obwohl sie langsam ausführen will, rufe ich gerade mein Skript wie folgt aus:

SLOW_TESTS=1 python -m unittest …

Sie haben grundsätzlich zwei Möglichkeiten, es zu tun:

  1. Definieren Sie eigene Reihe von Tests für die Klasse
  2. Erstellen Mock Klassen der Cluster-Verbindung, die aktuellen Daten angezeigt werden können.

Ich bin ein starker Befürworter der er den zweiten Ansatz; ein Unit-Test sollte Test nur eine sehr Einheit von Code, und nicht komplexe Systeme (wie Datenbanken oder Cluster). Aber ich verstehe, dass es nicht immer möglich ist; manchmal ist einfach mock ups zu schaffen zu teuer, oder das Ziel des Tests ist es wirklich in dem komplexen System.

Zurück zur Option (1), können Sie auf diese Weise vorgehen können:

suite = unittest.TestSuite()
suite.addTest(MyUnitTestClass('quickRunningTest'))
suite.addTest(MyUnitTestClass('otherTest'))

und dann die Suite zum Test Läufer übergeben:

unittest.TextTestRunner().run(suite)

Weitere Informationen über die Python-Dokumentation: http://docs.python.org /library/unittest.html#testsuite-objects

Da Sie verwenden unittest.main() Sie nur python tests.py --help ausführen können die Dokumentation zu erhalten:

Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase

Das heißt, können Sie einfach tun

python tests.py TestClass.test_method

Oder Sie können die unittest.SkipTest() Funktion machen. Beispiel eine skipOrRunTest Methode auf Ihre Testklasse wie folgt hinzu:

def skipOrRunTest(self,testType):
    #testsToRun = 'ALL'
    #testsToRun = 'testType1, testType2, testType3, testType4,...etc'
    #testsToRun = 'testType1'
    #testsToRun = 'testType2'
    #testsToRun = 'testType3'
    testsToRun = 'testType4'              
    if ((testsToRun == 'ALL') or (testType in testsToRun)):
        return True 
    else:
        print "SKIPPED TEST because:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

Dann ein Aufruf dieser Methode skipOrRunTest an den Anfang jeder Ihrer Unit-Tests wie folgt hinzu:

def testType4(self):
    self.skipOrRunTest('testType4')

fand ich eine andere Lösung, basierend darauf, wie der unittest.skip Dekorateur arbeitet. Durch die Einstellung der __unittest_skip__ und __unittest_skip_why__.

Label-basierende

Ich wollte ein Etikettierungssystem anwenden, einige Tests wie quick zu beschriften, slow, glacier, memoryhog, cpuhog, core, und so weiter.

Dann laufen all 'quick' tests oder run everything except 'memoryhog' tests, Ihre grundlegenden Weiße Liste / Schwarze Liste Setup

Die Umsetzung

I implementiert dies in 2 Teilen:

  1. Erste Beschriftungen hinzufügen, Tests (über eine benutzerdefinierte @testlabel Klasse Dekorateur)
  2. Benutzerdefinierte unittest.TestRunner zu identifizieren, welche überspringen testet, und ändern Sie den Testliste Inhalt vor der Ausführung.

Arbeits Umsetzung ist in diesem Kern: https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(ein voll funktionsfähiges Beispiel zu lang war hier zu setzen)

Das Ergebnis: ...

$ ./runtests.py --blacklist foo
test_foo (test_things.MyTest2) ... ok
test_bar (test_things.MyTest3) ... ok
test_one (test_things.MyTests1) ... skipped 'label exclusion'
test_two (test_things.MyTests1) ... skipped 'label exclusion'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK (skipped=2)

Alle MyTests1 Klasse Tests übersprungen werden, weil es das foo Etikett angegeben ist.

--whitelist auch funktioniert

Schauen Sie in ein dediziertes testrunner verwenden, wie py.test, Nase oder möglicherweise sogar zope.testing. Sie haben alle Befehlszeilenoptionen zur Auswahl von Tests.

Sehen Sie zum Beispiel als Nase: https://pypi.python.org/pypi /nose/1.3.0

Ich versuchte @ slott Antwort:

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Aber das gab mir die folgende Fehlermeldung:

Traceback (most recent call last):
  File "functional_tests.py", line 178, in <module>
    unittest.TextTestRunner().run(suite)
  File "/usr/lib/python2.7/unittest/runner.py", line 151, in run
    test(result)
  File "/usr/lib/python2.7/unittest/case.py", line 188, in __init__
    testMethod = getattr(self, methodName)
TypeError: getattr(): attribute name must be string

Die für mich folgende gearbeitet:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)

Ich habe einen anderen Weg gefunden, die test_ * Methoden auszuwählen, die ich nur durch Hinzufügen eines Attributs, um sie ausführen möchten. Sie verwenden im Grunde eine Metaklasse die Callables in der Testcase-Klasse zu schmücken, die die StepDebug mit einem unittest.skip Dekorateur Attribut haben. Weitere Informationen über

Skipping all Unit-Tests, sondern ein in Python von Dekorateuren und metaclasses

mit

Ich weiß nicht, ob es eine bessere Lösung als die oben Ich habe es als Option bin bereitstellt.

Haben Sie einen schönen Weg gefunden dies vor zu tun, so teilt hier.

Ziel: Erhalten Sie einen Satz von Testdateien zusammen, so dass sie als eine Einheit ausgeführt werden können, aber wir können immer noch einen von ihnen auswählen, indem Sie selbst auszuführen.

Problem: die Discover-Methode nicht erlaubt die einfache Auswahl eines einzigen Testfall ausführen

.

Entwurf: siehe unten. Diese flacht der Namespace kann durch Testcase Klassennamen so wählen, und lassen Sie den den „tests1.test_core“ Präfix:

./run-tests TestCore.test_fmap

Code

  test_module_names = [
    'tests1.test_core',
    'tests2.test_other',
    'tests3.test_foo',
    ]

  loader = unittest.defaultTestLoader
  if args:
    alltests = unittest.TestSuite()
    for a in args:
      for m in test_module_names:
        try:
          alltests.addTest( loader.loadTestsFromName( m+'.'+a ) )
        except AttributeError as e:
          continue
  else:
    alltests = loader.loadTestsFromNames( test_module_names )

  runner = unittest.TextTestRunner( verbosity = opt.verbose )
  runner.run( alltests )

Das ist das einzige, was für mich gearbeitet.

if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

Als ich es genannt, obwohl ich im Namen der Klasse und Testnamen zu übergeben hatte. Ein wenig umständlich, da ich Klasse und Testname nicht Kombination gespeichert.

Python ./tests.py class_Name.test_30311

Das Entfernen des Klassennamen und Testnamen führen alle Tests in der Datei. Ich finde dies viel einfacher zu handhaben dann in Verfahren der eingebauten da ich nicht wirklich mein Kommando auf der CLI ändern. Fügen Sie einfach den Parameter.

Genießen Sie

, Keith

habe ich einen Dekorateur, die für Markierungsversuche als langsame Tests und überspringen sie mit einer Umgebungsvariable

erlaubt
from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

Jetzt können Sie Ihre Tests so langsam wie folgt markieren:

@slow_test
def test_my_funky_thing():
    perform_test()

Und langsam Tests überspringen, indem die SKIP_SLOW_TESTS Umgebungsvariable:

SKIP_SLOW_TESTS=1 python -m unittest
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top