2012-09-19 11 views
20

Me gustaría que mi módulo de prueba de Python le diga al corredor de prueba que omita todo en algunas situaciones (como no poder importar un módulo o localizar un recurso crítico).¿Cómo omito un módulo de prueba de unidad de Python completo en tiempo de ejecución?

puedo usar @unittest.skipIf(...) saltarse una clase unittest.TestCase, pero ¿cómo puedo saltar la totalidad módulo? Aplicar saltos a cada clase no es suficiente porque las propias definiciones de clase podrían causar excepciones si un módulo no puede importar.

+2

Para su información, hay una publicación en el blog sobre esto en http://colinnewell.wordpress.com/2012/08/31/skippng-python-unit-tests-if-a-dependency-is-missing/ –

+1

@Mu Mind, esto funciona, excepto que le digo a 'nose' que" falle rápido ". Llamar a 'unittest.SkipTest() 'parece contar como una falla y detiene la ejecución. –

Respuesta

6

Después de mirar en el otro answe Aquí, esta es la mejor respuesta que he encontrado. Es feo, integra todo el conjunto de pruebas en el manejo de excepciones, pero parece hacer lo que quiere. Saltarse las pruebas específicamente cuando las importaciones no funcionan.

Suponiendo que está hablando de usar nosetests -x para ejecutar las pruebas, debe pasar las pruebas que omiten, al menos cuando lo probé.

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() 

Si la importación falla, reemplaza la ejecución de prueba con una sola prueba que simplemente omite. También intenté asegurarme de que no se traga ninguna excepción involuntariamente. Esta solución debe mucho a todas las demás respuestas y comentarios a la pregunta.

Si lo ejecuta en modo detallado verá esto cuando se salta,

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

Creo que esta es la mejor respuesta, pero tienes razón, es feo. :-) –

+0

Obteniendo 'DeprecationWarning: BaseException.message ha quedado obsoleto a partir de Python 2.6'? Debe hacer esto: http://stackoverflow.com/questions/1272138/baseexception-message-deprecated-in-python-2-6 – crazysim

2

Podría ser sucia para poner todas las unittest.TestCase definiciones de subclases en un bloque try...except pero funcionaría:

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

Ninguna de las subclases se definiría si la importación eggs falla y todos aquellos las clases() se saltan. No se reflejaría en el resultado (bueno o malo según lo que desee).

+0

Una solución sucia a un problema artificial no es tan mala;) –

+1

@Mu Mind, ¿es realmente artificial? Mi caso de uso es ejecutar el conjunto de pruebas en múltiples plataformas (algunas de las cuales pueden no ser capaces de "importar huevos"). –

+0

Casi siempre te estaba haciendo pasar un mal rato. Creo que el aspecto de las definiciones de clase no suena un poco extraño, pero deshabilitar "este módulo" parece más limpio que deshabilitar "todas las clases en este módulo" de todos modos. –

12

Si nos fijamos en la definición de unittest.skipIf y unittest.skip, puede ver que la clave está haciendo raise unittest.SkipTest(reason) cuando se ejecuta la prueba. Si estás de acuerdo con tener que aparece como uno saltado prueba en lugar de varios en la TestRunner, sólo tiene que levantar unittest.SkipTest a sí mismo en la importación:

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

Correr con nosetests -v da:

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

No sé si eso funcionaría en el alcance del * módulo *; 'loader.py' parece sugerir que el módulo falla si arroja * any * excepción. – nneonneo

+0

Lo intenté haciendo pruebas con nosetests y funcionó bien. Editando mi respuesta para agregar la salida real ... –

+2

'nosetests'! =' Unittest', aunque usan la misma biblioteca. Bastante seguro de que falla por simple 'unittest'. – nneonneo

2

Intenta definir una función personalizada load_tests en su módulo:

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

Me gusta este enfoque. Probablemente sería mejor si hiciera algún tipo de uso del mecanismo SkipTest en lugar de solo una 'impresión' ya que esa salida puede quedar ahogada en un montón de resultados/resultados de otras pruebas. –

+0

Es posible. Simplemente haga que 'TestSuite' contenga un caso de prueba ficticio que indique que se saltó. (El 'cargador' del módulo 'unittest' hace algo similar, produciendo casos de prueba de falla garantizada si, por ejemplo, una importación falla). – nneonneo

6

He encontrado que el uso de skipTest en la Configuración del funcionó bien. Si necesita importar un módulo, use un bloque de prueba para configurar, p. module_failed = Verdadero, y en setUp call skipTest si está configurado. Informa del número correcto de saltos de prueba con sólo una corta bloque try necesario:

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

El solution propuesto por obras Oto y es más fácil que la solución aceptada en mi opinión. Pero hay al menos un inconveniente.Si consulta my_module en un decorador de saltarse una sola prueba como

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

obtendrá un NameError: name 'my_module' is not defined. La solución se puso el salto dentro la definición de función:

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

La combinación de las respuestas mencionados y el uso de 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

para Python 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)) 
... 
Cuestiones relacionadas