2010-10-12 5 views
10

Estoy usando el módulo pytest unittest para hacer una serie de pruebas; sin embargo, es muy repetitivo.Cómo probar la misma aserción para una gran cantidad de datos

Tengo una gran cantidad de datos que quiero ejecutar a través de la misma prueba una y otra vez, verificando si es correcta. Sin embargo, tengo que definir una prueba para cada uno.

Por ejemplo, quiero hacer algo similar a esto. Sé que podría hacerlo usando un generador (lo encontré en un hilo anterior aquí). Pero hay alternativas, tal vez incluso utilizando un módulo de prueba diferente?

Cualquier sugerencia sería genial.


import unittest 

class TestData(unittest.TestCase): 
    def testNumbers(self): 
     numbers = [0,11,222,33,44,555,6,77,8,9999] 
     for i in numbers: 
      self.assertEqual(i, 33) 
+0

¿Qué hay de malo en esto? Se ve genial. –

+0

Básicamente, tan pronto como la afirmación sea verdadera, dejará de ejecutarse. – Mark

Respuesta

1

En otro post me encontré cruzando Nose Tests Es más se adapte a los datos de las pruebas conducidas.


class Test_data(): 
    def testNumbers(): 
     numbers = [0,11,222,33,44,555,6,77,8,9999] 
     for i in numbers: 
      yield checkNumber, num 

def checkNumber(num): 
    assert num == 33 

El código anterior hace exactamente lo mismo que mi primera publicación. No se necesitan importaciones, solo escriba una clase de Python.

Ejecuta las pruebas escribiendo:

nosetests filename

2

El problema con el funcionamiento de las afirmaciones en un bucle es que, si una de las afirmaciones falla, usted no sabe lo que hizo que el valor (en su ejemplo, que fracasaría en 0, pero no lo hace saber eso hasta que depure). Por otro lado, repetir self.assertEqual(i, 33) es una idea aún peor, porque introduce la duplicación de código.

Lo que hago en mi prueba es crear una función interna simple, brevemente nombrada dentro de la prueba y llamarla con diferentes argumentos. Por lo que su función se vería así:

import unittest 

class TestData(unittest.TestCase): 
    def testNumbers(self): 
     def eq(i): 
      self.assertEqual(i, 33) 
     eq(0) 
     eq(11) 
     eq(222) 
     eq(33) 
     eq(44) 
     eq(555) 
     ... 

esta manera, cuando la afirmación falla por 0, inmediatamente ve en el seguimiento de pila impresa por el módulo unittest.

+0

Veo lo que estás haciendo. Es una buena idea. Pero la primera vez que llegue a 33, dejará de ejecutarse para el resto del código. – Mark

+0

Si lo que dices es que tienes que recrear el accesorio de prueba para cada número, entonces debes seguir adelante con lo que Bill Gribble sugirió y construir dinámicamente un TestSuite. – DzinX

5

Es posible que desee considerar el uso de la clase unittest.TestSuite, que le permitirá construir dinámicamente un conjunto de instancias unittest.TestCase que se ejecutarán por separado. Su subclase unittest.TestCase debe definir solo un método de prueba, y la clase acepta un parámetro de construcción que pase en el valor para probar en contra de esa instancia particular.

9

Código de ejemplo para la solución sugerida por Bill Gribble podría tener este aspecto:

import unittest 

class DataTestCase(unittest.TestCase): 
    def __init__(self, number): 
     unittest.TestCase.__init__(self, methodName='testOneNumber') 
     self.number = number 

    def testOneNumber(self): 
     self.assertEqual(self.number, 33) 

    def shortDescription(self): 
     # We need to distinguish between instances of this test case. 
     return 'DataTestCase for number %d' % self.number 


def get_test_data_suite(): 
    numbers = [0,11,222,33,44,555,6,77,8,9999] 
    return unittest.TestSuite([DataTestCase(n) for n in numbers]) 

if __name__ == '__main__': 
    testRunner = unittest.TextTestRunner() 
    testRunner.run(get_test_data_suite()) 
1

El ddt library fue construido para resolver exactamente lo que están pidiendo.

Por ejemplo:

import ddt 
import unittest 

@ddt.ddt 
class EvalTests(unittest.TestCase): 

    @ddt.data(
      ('1', 1), 
      ('1 == 1', True), 
      ('1 == 2', False), 
      ('1 + 2', 4), ## This will fail 
    ) 
    def test_eval_expressions(self, case): 
     expr, exp_value = case 
     self.assertEqual(eval(expr), exp_value) 

Y cuando se ejecuta, se obtiene 4 casos que sienta jurisprudencia lugar de uno solo:

$ python -m unittest -v test_eval.py 
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok 
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok 
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok 
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL 

====================================================================== 
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper 
    return func(self, *args, **kwargs) 
    File "/Work/test_eval.py", line 15, in test_eval_expressions 
    self.assertEqual(eval(expr), exp_value) 
AssertionError: 3 != 4 

---------------------------------------------------------------------- 
Ran 4 tests in 0.002s 

FAILED (failures=1) 

en cuenta que ddt intenta subir con nombres para la generada TCs.

instalarlo con pip:

pip install ddt 
0

spin-off de this respuesta, que hizo el trabajo no es para mí. Cuando no estoy tratando con grandes cantidades de datos, sí tuve que ejecutar las mismas pruebas con diferentes entradas. Las siguientes pruebas usan los métodos create_a y create_b que quiero personalizar.

El requisito es ejecutar ambas pruebas con la misma personalización.

class Tests(unittest.TestCase): 

    def test_a_uses_b(self): 
     a = create_a() 
     b = create_b() 
     a.b = b 
     self.assertIs(b.a, a) 

    def test_b_uses_a(self): 
     a = create_a() 
     b = create_b() 
     b.a = a 
     self.assertIs(a.b, b) 

Instanciando TestSuite y TestCase a mí mismo, sin pasar por el cargador de prueba, dio lugar a un error, ya que espera que un solo método, llamado runTest.

El resultado fue el siguiente:

class Tests(unittest.TestCase): 

    def __init__(self, create_a, create_b): 
     super().__init__() 
     self.create_b = create_b 
     self.create_a = create_a 

    def test_a_uses_b(self): 
     a = self.create_a() 
     b = self.create_b() 
     a.b = b 
     self.assertIs(b.a, a) 

    def test_b_uses_a(self): 
     a = self.create_a() 
     b = self.create_b() 
     b.a = a 
     self.assertIs(a.b, b) 


class TestPair1(Tests): 
    def __init__(self): 
     super().__init__(create_a1, create_b1) 


class TestPair2(Tests): 
    def __init__(self): 
     super().__init__(create_a2, create_b2) 
Cuestiones relacionadas