2014-05-16 10 views
9

Wow. Ich habe heute Nacht herausgefunden, dass Python-Unit-Tests, die mit dem unittest-Modul geschrieben wurden, nicht gut mit der Coverage-Analyse unter dem trace-Modul funktionieren. Hier ist die einfachste mögliche Unit-Test, in foobar.py:unittest.py spielt nicht gut mit trace.py - warum?

import unittest 

class Tester(unittest.TestCase): 
    def test_true(self): 
     self.assertTrue(True) 

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

Wenn ich diese laufen mit python foobar.py, erhalte ich diese Ausgabe:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK 

Großen. Jetzt möchte ich Deckung Tests so gut funktioniert, so dass ich laufen sie wieder mit python -m trace --count -C . foobar.py, aber jetzt bekomme ich diese:

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

OK 

Nein, Python, es ist nicht in Ordnung - du hast nicht mein Test laufen! Es scheint, als ob es im Rahmen von trace läuft, gumt up unittest 's Test Erkennungsmechanismus. Hier ist die (verrückt) Lösung, die ich kam mit:

import unittest 

class Tester(unittest.TestCase): 
    def test_true(self): 
     self.assertTrue(True) 

class Insane(object): 
    pass 

if __name__ == "__main__": 
    module = Insane() 
    for k, v in locals().items(): 
     setattr(module, k, v) 

    unittest.main(module) 

Dies ist im Grunde eine Abhilfe, die die abstrakten, unnameable Namen des Top-Level-Modul verdinglicht durch eine Kopie davon vorgetäuscht werden. Ich kann dann diesen Namen an unittest.main() übergeben, um so zu umgehen, was auch immer trace auf es hat. Keine Notwendigkeit, Ihnen die Ausgabe zu zeigen; Es sieht genauso aus wie das erfolgreiche Beispiel oben.

Also, ich habe zwei Fragen:

  1. Was ist hier los? Warum macht trace vermasseln für unittest?

  2. Gibt es eine einfachere und/oder weniger wahnsinnige Möglichkeit, dieses Problem zu umgehen?

Antwort

7

Eine einfachere Abhilfe ist, den Namen des Moduls explizit unittest.main weitergeben müssen:

import unittest 

class Tester(unittest.TestCase): 
    def test_true(self): 
     self.assertTrue(True) 

if __name__ == "__main__": 
    unittest.main(module='foobar') 

trace vermasselt Test Entdeckung in unittest wegen wie trace lädt das Modul es läuft. trace liest den Modulquellcode, kompiliert ihn und führt ihn in einem Kontext mit einer globalen __name__-Gruppe aus, die auf '__main__' festgelegt ist. Dies reicht aus, um die meisten Module so zu verhalten, als ob sie als Hauptmodul aufgerufen würden, ändert jedoch nicht das Modul, das im Python-Interpreter als __main__ registriert ist. Wenn unittest nach dem Modul __main__ fragt, um nach Testfällen zu suchen, erhält es tatsächlich das trace-Modul, das von der Befehlszeile aufgerufen wird, das natürlich die Komponententests nicht enthält.

coverage.py nimmt einen anderen Ansatz des tatsächlichen Ersetzens, welches Modul __main__ in heißt.

+0

Große Erklärung, danke. Ich muss dem Testmodul nur sagen, was sein eigener (Datei-) Name ist und es funktioniert wie ein Zauber, sowohl für sich selbst als auch unter trace.py. –

+0

BTW: zu versuchen, cProfile und unittest mit 'python -m cProfile [some_test_file.py]' hat das gleiche Problem, und die gleiche Lösung: 'unittest.main (module = 'Tests')'. Suchmaschinen haben nichts gefunden, was für cProfile spezifisch ist, also fügen Sie einen Kommentar hinzu, um die Suche zu erleichtern. –

3

Ich weiß nicht, warum trace nicht richtig funktioniert, aber coverage.py tut:

$ coverage run foobar.py 
. 
---------------------------------------------------------------------- 
Ran 1 test in 0.001s 

OK 
$ coverage report 
Name  Stmts Miss Cover 
---------------------------- 
foobar  6  0 100% 
+0

Ich mag coverage.py, aber ich bin zu trace.py gewechselt, weil ich die * .cover-Dateien benötigt habe (für die automatische Coverage-Analyse, die von CDash ausgeführt wird). Gibt es eine Möglichkeit, coverage.py zum Senden dieser Dateien zu erhalten? –

+0

Ich weiß nicht, was in einer .cover-Datei ist, aber es kann nicht so schwer sein, sie aus den Daten coverage.py zu sammeln. Kontaktieren Sie uns per E-Mail, damit wir darüber sprechen können. –