2014-05-16 17 views
9

Wow. Ho scoperto stasera che i test delle unità Python scritti usando il modulo unittest non giocano bene con l'analisi della copertura sotto il modulo trace. Ecco la più semplice test di unità possibile, in foobar.py:unittest.py non funziona bene con trace.py - perché?

import unittest 

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

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

Se corro questo con python foobar.py, ottengo questo output:

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

OK 

Grande. Ora voglio eseguire test di copertura e, quindi corro di nuovo con python -m trace --count -C . foobar.py, ma ora ottengo questo:

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

OK 

No, Python, non è OK - non è stato eseguito il test! Sembra che l'esecuzione nel contesto di trace in qualche modo aumenti il ​​meccanismo di rilevamento del test unittest. Ecco la soluzione (folle) mi si avvicinò con:

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) 

Questo è fondamentalmente una soluzione che reifica il, nome innominabile astratta del modulo di livello superiore fingendo una copia di esso. Posso quindi passare quel nome a unittest.main() in modo da eludere l'effetto su di esso con lo trace. Non c'è bisogno di mostrarti l'output; sembra proprio come l'esempio di successo sopra.

Così, ho due domande:

  1. cosa sta succedendo qui? Perché lo trace rovina le cose per unittest?

  2. C'è un modo più semplice e/o meno folle per aggirare questo problema?

risposta

7

Una soluzione più semplice è quello di passare il nome del modulo in modo esplicito a unittest.main:

import unittest 

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

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

trace rovina la scoperta del test in unittest a causa del modo in cui trace carica il modulo sta correndo. trace legge il codice sorgente del modulo, lo compila e lo esegue in un contesto con un insieme globale __name__ su '__main__'. Questo è sufficiente per far sì che la maggior parte dei moduli si comportino come se fossero chiamati come il modulo principale, ma in realtà non cambia il modulo che è registrato come __main__ nell'interprete Python. Quando unittest richiede il modulo __main__ per eseguire la scansione dei casi di test, riceve effettivamente il modulo trace chiamato dalla riga di comando, che ovviamente non contiene i test delle unità.

coverage.py prende un approccio diverso di sostituire effettivamente quale modulo è chiamato __main__ in sys.modules.

+0

Ottima spiegazione, grazie. Devo solo dire al modulo di test il suo nome (file) e funziona come un incantesimo, sia da solo che sotto trace.py. –

+0

BTW: provare ad usare cProfile e unittest con 'python -m cProfile [some_test_file.py]' ha lo stesso problema, e la stessa soluzione: 'unittest.main (module = 'tests')'. I motori di ricerca non hanno trovato nulla di specifico per cProfile, quindi aggiungendo un commento per cercare di aiutare la ricerca. –

3

Non so perché trace non funziona correttamente, ma coverage.py fa:

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

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

Mi piace coverage.py, ma sono passato a trace.py perché avevo bisogno dei file * .cover che genera (per analisi di copertura automatizzata eseguite da CDash). C'è un modo per ottenere coverage.py per emettere questi file? –

+0

Non so cosa ci sia in un file .cover, ma non potrebbe essere così difficile renderli dai dati che coverage.py raccoglie. Mettiti in contatto con l'e-mail in modo che possiamo parlarne. –

Problemi correlati