Pregunta

Tengo un archivo de prueba que contiene pruebas que toman bastante tiempo (envían cálculos a un clúster y esperan el resultado).Todos estos están en una clase TestCase específica.

Dado que toman tiempo y además no es probable que se rompan, me gustaría poder elegir si este subconjunto de pruebas se ejecuta o no (la mejor manera sería con un argumento de línea de comandos, es decir, "./tests.py --offline" o algo así), para poder ejecutar la mayoría de las pruebas con frecuencia y rapidez y todo el conjunto de vez en cuando, cuando tenga tiempo.

Por ahora solo uso unittest.main() para iniciar las pruebas.

Gracias.

¿Fue útil?

Solución

El valor predeterminado unittest.main() usa el gestor de prueba predeterminado para hacer una TestSuite fuera del módulo en el que se está ejecutando principal.

Usted no tiene que utilizar este comportamiento por defecto.

Puede, por ejemplo, hacer tres casos unittest.TestSuite .

  1. El subconjunto "rápida".

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. El "lento" subconjunto.

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. El "conjunto" establecido.

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

Tenga en cuenta que he ajustado los nombres TestCase para indicar vs Rápido Lento. Usted puede subclase unittest.TestLoader para analizar los nombres de las clases y crear múltiples cargadores.

A continuación, el programa principal puede analizar los argumentos de línea de comandos con optparse o argparse (disponible desde 2.7 o 3.2) para recoger el cual privado que desee ejecutar, rápido, lento o todos.

O, puede confiar en que sys.argv[1] es uno de los tres valores y el uso de algo tan simple como esto

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

Otros consejos

Para ejecutar una única prueba específica que puede utilizar:

$ python -m unittest test_module.TestClass.test_method

Más información aquí

En realidad, se puede pasar los nombres del caso de prueba como sys.argv y se pondrá a prueba sólo aquellos casos.

Por ejemplo, suponga que tiene

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

Puede llamar

python test.py account

para tener pruebas de cuenta sólo, o incluso

$ python test.py account customer

tener ambos casos probados

Estoy haciendo esto mediante un sencillo skipIf:

import os

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

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

De esta manera solo me falta decorar un caso de prueba ya existente con esta sola línea (sin necesidad de crear bancos de pruebas o similares, sólo que uno os.getenv() línea de llamada en el comienzo de mi archivo de prueba de unidad), y como predeterminado esta prueba es ignorada.

Si quiero ejecutarlo a pesar de ser lento, acabo de llamar a mi script como el siguiente:

SLOW_TESTS=1 python -m unittest …

Hay básicamente dos maneras de hacerlo:

  1. Definir su propio conjunto de pruebas para la clase
  2. Crear clases simuladas de la conexión de clúster que devolverá los datos reales.

Soy un firme defensor de que el segundo enfoque; una prueba de unidad debe prueba sólo una unidad de código, y no los sistemas complejos (como bases de datos o clusters). Pero entiendo que no siempre es posible; A veces, la creación de maquetas es simplemente demasiado caro, o el objetivo de la prueba es realmente en el sistema complejo.

Volver a la opción (1), se puede proceder de esta manera:

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

y luego pasando la suite con el corredor de prueba:

unittest.TextTestRunner().run(suite)

Más información en la documentación de Python: http://docs.python.org /library/unittest.html#testsuite-objects

Desde utiliza unittest.main() que sólo puede funcionar python tests.py --help para obtener la documentación:

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

Es decir, sólo tiene que hacer

python tests.py TestClass.test_method

O bien, puede hacer uso de la función de unittest.SkipTest(). Ejemplo, agregue un método skipOrRunTest a su clase de prueba como esta:

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!!!")

A continuación, agregue una llamada a este método skipOrRunTest al principio de cada una de las pruebas unitarias como esto:

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

Encontré otra solución, basada en cómo unittest.skip trabajos de decorador.Al configurar el __unittest_skip__ y __unittest_skip_why__.

Basado en etiquetas

Quería aplicar un sistema de etiquetado, etiquetar algunas pruebas como quick, slow, glacier, memoryhog, cpuhog, core, etcétera.

Entonces corre all 'quick' tests, o run everything except 'memoryhog' tests, su configuración básica de lista blanca/lista negra

Implementación

Implementé esto en 2 partes:

  1. Primero agregue etiquetas a las pruebas (a través de un personalizado @testlabel decorador de clase)
  2. Costumbre unittest.TestRunner para identificar qué pruebas omitir y modificar el contenido de la lista de pruebas antes de ejecutar.

La implementación funcional se resume en esta esencia:https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(un ejemplo completamente funcional fue demasiado largo para ponerlo aquí)

El resultado es...

$ ./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)

Todo MyTests1 Los exámenes de clase se omiten porque tiene la foo etiqueta.

--whitelist también funciona

Mira en el uso de un TestRunner dedicado, como py.test, la nariz o posiblemente incluso zope.testing. Todos ellos tienen opciones de línea de comandos para la selección de pruebas.

Mire por ejemplo, como la nariz: https://pypi.python.org/pypi /nose/1.3.0

He intentado @ respuesta de Slott:

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

Pero eso me dio el siguiente error:

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

Los siguientes trabajó para mí:

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

He encontrado otra forma de seleccionar la test_ * métodos que sólo desea ejecutar mediante la adición de un atributo a ellos. Es, básicamente, utiliza una metaclase para decorar las callables dentro de la clase TestCase que tienen el atributo StepDebug con un decorador unittest.skip. Más información sobre

Saltarse todas las pruebas unitarias pero uno en Python mediante el uso de decoradores y metaclases

No sé si es una solución mejor que los de arriba estoy limitarse a proporcionar como una opción.

No has encontrado una buena manera de hacer esto antes, lo que podrá compartir aquí.

Objetivo: Obtener un conjunto de archivos de prueba juntos para que puedan ser ejecutados como una unidad, pero todavía podemos seleccionar cualquiera de ellos para funcionar por sí mismo.

Problema: el método de descubrimiento no permiten una fácil selección de un solo caso de prueba para ejecutar

.

Diseño: ver a continuación. Este aplana por lo que el espacio de nombres puede seleccionar el nombre de la clase TestCase, y dejar fuera de la la "tests1.test_core" prefijo:

./run-tests TestCore.test_fmap

Código

  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 )

Esto es lo único que trabajó para mí.

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

Cuando me llamaron a pesar de que tenía que pasar el nombre del nombre de la clase y de prueba. Un pequeño inconveniente, ya que no tienen clase y nombre de la prueba combinación memorizado.

pitón ./tests.py class_Name.test_30311

La eliminación del nombre de la clase y el nombre de la prueba se ejecuta todas las pruebas en su archivo. Me parece mucho más fácil de tratar a continuación el construido en el método, ya que realmente no cambie de comando en la CLI. Sólo tiene que añadir el parámetro.

Disfrute, Keith

I creado un decorador que permite la corrección de las pruebas como pruebas lentas y para saltar ellos utilizando una variable de entorno

from unittest import skip
import os

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

Ahora puede marcar sus pruebas tan lento como esto:

@slow_test
def test_my_funky_thing():
    perform_test()

Y omitir pruebas lentas estableciendo la variable de entorno SKIP_SLOW_TESTS:

SKIP_SLOW_TESTS=1 python -m unittest
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top