2012-09-19 12 views
20

Vorrei che il mio modulo di unificatore di Python dicesse al test runner di saltare la sua interezza in alcune situazioni (come non essere in grado di importare un modulo o localizzare una risorsa critica).Come saltare un intero modulo unittest Python in fase di esecuzione?

Posso usare @unittest.skipIf(...) per saltare una classe unittest.TestCase, ma come faccio a saltare l'intero modulo ? L'applicazione dei salti a ogni classe non è sufficiente perché le definizioni di classe stesse potrebbero causare eccezioni se un modulo non riesce a importare.

+2

FYI, c'è un post sul blog su questa cosa esatta su http://colinnewell.wordpress.com/2012/08/31/skippng-python-unit-tests-if-a-dipendenza-is-missing/ –

+1

@Mu Mind, questo funziona eccetto che sto dicendo 'nose' to "fail fast". Chiamare 'unittest.SkipTest()' sembra contare come un fallimento e interrompe l'esecuzione. –

risposta

6

Dopo guardando l'altro answe qui, questa è la migliore risposta che ho trovato. È brutto, incorporando l'intera suite di test nella gestione delle eccezioni, ma sembra che faccia ciò che vuoi. Saltare in modo specifico i test quando le importazioni non funzionano.

Supponendo che si stia utilizzando l'uso di nosetest -x per l'esecuzione dei test, dovrebbe passare oltre i test che saltano, almeno a quanto sembrava quando l'ho provato.

import unittest 
try: 
    import PyQt4 
    # the rest of the imports 


    # actual tests go here. 
    class TestDataEntryMixin(unittest.TestCase): 
     def test_somefeature(self): 
      # .... 

except ImportError, e: 
    if e.message.find('PyQt4') >= 0: 
     class TestMissingDependency(unittest.TestCase): 

      @unittest.skip('Missing dependency - ' + e.message) 
      def test_fail(): 
       pass 
    else: 
     raise 

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

Se l'importazione fallisce, sostituisce l'esecuzione di test con un singolo test che salta semplicemente. Ho anche cercato di assicurarmi che non ingerisse eccezioni involontariamente. Questa soluzione deve molto a tutte le altre risposte e commenti alla domanda.

Se lo si esegue in modalità dettagliata si vedrà questo quando si salta,

test_fail (test_openihm_gui_interface_mixins.TestMissingDependency) ... skipped 'Missing dependency - No module named PyQt4' 
+0

Penso che questa sia la migliore risposta, ma hai ragione, è brutta. :-) –

+0

Ottenere 'DeprecationWarning: BaseException.message è stato deprecato da Python 2.6'? Hai bisogno di fare questo: http://stackoverflow.com/questions/1272138/baseexception-message-deprecated-in-python-2-6 – crazysim

2

Potrebbe essere sporco di mettere tutte le definizioni unittest.TestCase sottoclasse in un blocco try...except ma che avrebbe funzionato:

import unittest 
try: 
    import eggs 
    class Spam(unittest.TestCase): 
     pass 
    class Ham(unittest.TestCase): 
     pass 
    # ... 
except ImportError: 
    # print 'could not import eggs' 
    pass 

Nessuno dei sottoclassi sarebbe definito se l'importazione eggs fallisce e tutti coloro classi() vengono saltate. Non si rifletterebbe nell'output (buono o cattivo a seconda di ciò che si desidera).

+0

Una soluzione sporca a un problema inventato non è poi così male;) –

+1

@Mu Mind, è davvero inventato? Il mio caso d'uso sta eseguendo la suite di test su piattaforme multiple (alcune delle quali potrebbero non essere in grado di "importare uova"). –

+0

Ti stavo quasi dando del filo da torcere. Penso che la parte relativa alle definizioni di classi che hanno un suono un po 'strano, ma disabilitare "questo modulo" sembra più pulito che disabilitare "tutte le classi in questo modulo" comunque. –

12

Se si guarda la definizione di unittest.skipIf e unittest.skip, è possibile vedere che la chiave sta facendo raise unittest.SkipTest(reason) quando il test viene eseguito. Se stai bene con avere lo mostrano come uno saltati prova invece di più nel testrunner, si può semplicemente sollevare unittest.SkipTest te stesso durante l'importazione:

import unittest 
try: 
    # do thing 
except SomeException: 
    raise unittest.SkipTest("Such-and-such failed. Skipping all tests in foo.py") 

Running with nosetests -v dà:

Failure: SkipTest (Such-and-such failed. Skipping all tests in foo.py) ... SKIP: 
Such-and-such failed. Skipping all tests in foo.py 

---------------------------------------------------------------------- 
Ran 1 test in 0.002s 

OK (SKIP=1) 
+0

Non so se funzionerebbe allo scopo * modulo *; 'loader.py' sembra suggerire che il modulo fallisce se lancia * qualsiasi * eccezione. – nneonneo

+0

Ho provato a eseguire test con nosetests e ha funzionato bene. Modifica la mia risposta per aggiungere l'output effettivo ... –

+2

'nosetests'! =' Unittest', anche se usano la stessa libreria. Abbastanza sicuro che fallisca per un semplice 'unittest'. – nneonneo

2

Prova la definizione di una funzione personalizzata load_tests nel vostro modulo:

import unittest 
try: 
    (testcases) 
except ImportError as e: 
    def load_tests(*args, **kwargs): 
     print("Failed to load tests: skipping") 
     return unittest.TestSuite() # no tests 
+1

Mi piace questo approccio. Probabilmente sarebbe meglio se facesse uso del meccanismo SkipTest piuttosto che di una 'stampa', poiché quell'output può essere soffocato da una serie di altri risultati/risultati di test. –

+0

È possibile. Basta che il 'TestSuite' contenga un caso test fittizio che dice che è stato saltato. (Il 'loader' del modulo' unittest' fa una cosa simile, producendo casi di test di fallimento garantito se, per esempio, un'importazione fallisce). – nneonneo

6

ho trovato che l'uso di skipTest nel programma di installazione ha funzionato bene. Se hai bisogno di un modulo importato, puoi utilizzare un blocco try per impostare ad es. module_failed = True, e nella chiamata setUp skipTest se è impostato. Questo riporta il numero corretto di salti di prova con solo un breve blocco try necessario:

import unittest 

try: 
    import my_module 
    module_failed = False 
except ImportError: 
    module_failed = True 

class MyTests(unittest.TestCase): 
    def setUp(self): 
     if module_failed: 
      self.skipTest('module not tested') 

    def test_something(self): 
      #... 
3

Il solution proposto da opere Oto ed è più facile che la soluzione accettata a mio parere. Ma c'è almeno un aspetto negativo.Se si esegue una query my_module in un decoratore di saltare un singolo test, come

@unittest.skipIf(my_module.support_foo, 'foo not supported') 
def test_foo(self): 
... 

si otterrà un NameError: name 'my_module' is not defined. La soluzione viene messa la cesta all'interno la definizione della funzione:

def test_foo(self): 
    if not my_module.support_foo: 
     self.skipTest('foo not supported') 
0

Combinando le risposte menzionate e utilizzando this answer:

import unittest 
def module_exists(module_name): 
    try: 
     __import__(module_name) 
    except ImportError: 
     return False 
    else: 
     return True 

class TestClass(unittest.TestCase): 

    @unittest.skipUnless(module_exists("moduleA"), 'ModuleA not installed') 
    def test_something(self): 
     # test something with moduleA 
1

Per pitone 2.7+ (o usando backport unittest2):

... 

import unittest 

def setUpModule(): 
    try: 
     import something 
    except ImportError as err: 
     raise unittest.SkipTest(str(err)) 

class Tests(unittest.TestCase): 
    @classmethod 
    def setUpClass(cls): 
     try: 
      import something 
     except ImportError as err: 
      raise unittest.SkipTest(str(err)) 
... 
Problemi correlati