unittest unit test run modules examples example español assertraises python unit-testing pyunit

run - unittest python 3



Prueba de unidad de Python: ¿cómo ejecutar solo una parte de un archivo de prueba? (13)

Como usas unittest.main() puedes ejecutar 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, puedes simplemente hacer

python tests.py TestClass.test_method

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

Como 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í), por lo que podría ejecutar la mayoría de las pruebas a menudo y rápidamente y todo el conjunto de vez en cuando, cuando tenga tiempo.

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

Gracias.


Considera usar un testrunner dedicado, como py.test, nose o posiblemente incluso zope.testing. Todos ellos tienen opciones de línea de comando para seleccionar pruebas.

Busque, por ejemplo, Nose: https://pypi.python.org/pypi/nose/1.3.0


El unittest.main() predeterminado usa el cargador de prueba predeterminado para hacer que TestSuite salga del módulo en el que se está ejecutando main.

No tiene que usar este comportamiento predeterminado.

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

  1. El subconjunto "rápido".

    fast = TestSuite() fast.addTests( TestFastThis ) fast.addTests( TestFastThat )

  2. El subconjunto "lento".

    slow = TestSuite() slow.addTests( TestSlowAnother ) slow.addTests( TestSlowSomeMore )

  3. El conjunto "completo".

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

Tenga en cuenta que he ajustado los nombres de TestCase para indicar Fast vs. Slow. Puede subclasificar unittest.TestLoader para analizar los nombres de las clases y crear varios cargadores.

Entonces su programa principal puede analizar argumentos de línea de comando con optparse o argparse (disponible desde 2.7 o 3.2) para elegir qué suite desea ejecutar, rápida, lenta o todas.

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

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


En realidad, uno puede pasar los nombres del caso de prueba como sys.argv y solo esos casos serán probados.

Por ejemplo, supongamos que tiene

class TestAccount(unittest.TestCase): ... class TestCustomer(unittest.TestCase): ... class TestShipping(unittest.TestCase): ... account = TestAccount customer = TestCustomer shipping = TestShipping

Puedes llamar

python test.py account

tener solo pruebas de cuenta, o incluso

$ python test.py account customer

tener ambos casos probados


Encontré otra solución, basada en cómo funciona el decorador unittest.skip . Configurando __unittest_skip__ y __unittest_skip_why__ .

Basado en etiquetas

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

A continuación, ejecute 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 decorador de clases @testlabel personalizado)
  2. Custom unittest.TestRunner para identificar qué pruebas omitir y modificar el contenido de la lista de prueba antes de ejecutar.

La implementación operativa está 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)

Todas las pruebas de la clase MyTests1 se omiten porque tienen la etiqueta foo .

--whitelist también funciona


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

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

Cuando lo llamé, tuve que pasar el nombre de la clase y el nombre de la prueba. Un poco inconveniente ya que no tengo la combinación de nombre de clase y prueba memorizada.

python ./tests.py class_Name.test_30311

Al eliminar el nombre de clase y el nombre de prueba, se ejecutan todas las pruebas en su archivo. Encuentro esto MUCHO más fácil de tratar que el método integrado, ya que realmente no cambio mi comando en la CLI. Solo agrega el parámetro.

Disfruta, Keith


Estoy haciendo esto usando un skipIf simple:

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 necesito decorar un caso de prueba ya existente con esta única línea (no es necesario crear suites de prueba o similares, solo esa línea de llamada os.getenv() al principio del archivo de prueba de mi unidad), y de manera predeterminada esto la prueba se omite.

Si quiero ejecutarlo a pesar de ser lento, simplemente llamo a mi script de esta manera:

SLOW_TESTS=1 python -m unittest …


He encontrado otra manera de seleccionar los métodos test_ * que solo quiero ejecutar agregando un atributo a ellos. Básicamente, utilizas una metaclase para decorar los 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 menos una en Python usando decoradores y metaclases

No sé si es una solución mejor que las anteriores, solo la estoy ofreciendo como una opción.


Intenté la 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

Lo siguiente funcionó para mí:

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


No he encontrado una buena manera de hacer esto antes, así que comparto aquí.

Objetivo: obtener un conjunto de archivos de prueba para que puedan ejecutarse como una unidad, pero aún así podemos seleccionar cualquiera de ellos para que se ejecute solo.

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

Diseño: ver abajo. Esto aplana el espacio de nombres para que pueda seleccionar por nombre de clase TestCase, y deje el prefijo "tests1.test_core":

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


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

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 comienzo de cada una de las pruebas de su unidad como esta:

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


Para ejecutar solo una prueba específica, puede usar:

$ python -m unittest test_module.TestClass.test_method

Más información here


Tienes básicamente dos formas de hacerlo:

  1. Define tu propio conjunto de pruebas para la clase
  2. Cree clases simuladas de la conexión del clúster que devolverá los datos reales.

Soy un fuerte defensor del segundo enfoque; una prueba unitaria debe probar solo una unidad de código y no sistemas complejos (como bases de datos o clusters). Pero entiendo que no siempre es posible; a veces, crear maquetas es simplemente demasiado caro, o el objetivo de la prueba es realmente el complejo sistema.

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

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

y luego pasar la suite al corredor de prueba:

unittest.TextTestRunner().run(suite)

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