2011-06-14 10 views
9

¿Cómo puedo ejecutar la misma prueba con una gran cantidad de datos diferentes? Quiero que se me informe de todas las fallas.Proporcionando datos de prueba en python

Por ejemplo:

def isEven(number): 
    return True # quite buggy implementation 

data = [ 
    (2, True), 
    (3, False), 
    (4, True), 
    (5, False), 
] 

class MyTest: 
    def evenTest(self, num, expected): 
     self.assertEquals(expected, isEven(num)) 

he encontrado solución que plantea error en sólo el primer fracaso: http://melp.nl/2011/02/phpunit-style-dataprovider-in-python-unit-test/

Cómo ejecutar la prueba para ser informado de todos los fracasos?

Respuesta

5

Debería utilizar py.test, creo módulo unittest fue copiado ciegamente de JUnit, de todos modos puede abrirse paso como éste

import unittest 

data = [ 
    (2, True), 
    (3, False), 
    (4, True), 
    (5, False)] 

# this should be imported from a separate module. 
def isEven(number): 
    return True # quite buggy implementation 

def create_test_func(num, expected): 
    def _test_func(self): 
     self.assertEqual(expected, isEven(num)) 
    return _test_func 

class TestIsEven(unittest.TestCase): 

    pass 

# pyunit isn't pythonic enought use py.test instead 
# till then we rely on such hackery 
import new 
for i, (num, expected) in enumerate(data): 
    setattr(TestIsEven, 'test_data_%d'%i, create_test_func(num, expected)) 

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

y la salida es:

.F.F 
====================================================================== 
FAIL: test_data_1 (__main__.TestIsEven) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "untitled-1.py", line 15, in _test_func 
    self.assertEqual(expected, isEven(num)) 
AssertionError: False != True 

====================================================================== 
FAIL: test_data_3 (__main__.TestIsEven) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "untitled-1.py", line 15, in _test_func 
    self.assertEqual(expected, isEven(num)) 
AssertionError: False != True 

---------------------------------------------------------------------- 
Ran 4 tests in 0.000s 

FAILED (failures=2) 

Usando este enfoque se puede agregar más detalles como la información de depuración de errores, etc.

+0

+1, en 'Creo que el módulo unittest fue copiado ciegamente de junit' y es no es el único que se copió de java :) – mouad

-1
import unittest 

data = [ 
    (2, True), 
    (3, False), 
    (4, True), 
    (5, False)] 

# this should be imported from a separate module. 
def isEven(number): 
    return True # quite buggy implementation 


class TestIsEven(unittest.TestCase): 
    def test_is_even(self): 
     for num, expected in data: 
      self.assertEqual(expected, isEven(num)) 
+0

Esto plantea en el primer error - leer el final de la pregunta de nuevo. –

7

Una solución es hacer que diferentes instancias de casos de prueba para cada entrada en data:

class MyTest(unittest.TestCase): 
    def __init__(self, num, expected): 
     unittest.TestCase.__init__(self, "evenTest") 
     self.num = num 
     self.expected = expected 
    def evenTest(self): 
     self.assertEqual(self.expected, isEven(self.num)) 

Para unittest saber cómo construir los casos de prueba, añadir una función load_tests() a su módulo:

def load_tests(loader, tests, pattern): 
    return unittest.TestSuite(MyTest(num, expected) 
           for num, expected in data) 
3

¿Está buscando algo como esto:

import unittest 


def is_even(number): 
    return True # quite buggy implementation 


class TestCase(unittest.TestCase): 
    def setUp(self): 
     self.expected_output = [ 
      (2, True), 
      (3, False), 
      (4, True), 
      (5, False) 
     ] 

    def test_is_even(self): 
     real_res = [] 

     for arg, _ in self.expected_output: 
      real_res.append((arg, is_even(arg))) 

     msg_error = '\nFor %s Expected %s Got %s' 
     msg = [] 
     for res1, res2 in zip(real_res, self.expected_output): 
      if res1[1] != res2[1]: 
       msg.append(msg_error % (res1[0], res1[1], res2[1])) 


     self.assertEqual(real_res, self.expected_output, "".join(msg)) 


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

Salida:

F 
====================================================================== 
FAIL: test_is_even (__main__.TestCase) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "test.py", line 29, in test_example 
    self.assertEqual(real_res, self.expected_output, ''.join(msg)) 
AssertionError: 
For 3 Expected True Got False 
For 5 Expected True Got False 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (failures=1) 
+0

Si tuviera 50 pruebas, de las cuales 10 fallan, será difícil encontrar lo que está pasando. Para un conjunto pequeño de datos de prueba simples, será muy útil y útil. Gracias :) – jinowolski

+2

@jinowolski: Es cierto, con gusto podemos personalizar el mensaje de error tanto como queramos edité mi respuesta, no sé si esto funciona para usted. – mouad

+0

pero todavía es 1 prueba –

2

Si está usando pytest y ou puede ir de esta manera:

import pytest                             

def is_even(number): 
    return True # quite buggy implementation 

@pytest.mark.parametrize("number, expected", [ 
    (2, True), 
    (3, False), 
    (4, True), 
    (5, False) 
]) 
def test_is_even(number, expected): 
    assert is_even(number) == expected 

Va a conseguir algo como (acortada):

/tmp/test_it.py:13: AssertionError 
=========== 2 failed, 2 passed in 0.01 seconds ==================== 
+0

Tal vez marcar parametrize no existía cuando se aportaron las otras respuestas, pero esta parece ser la respuesta correcta aquí. –

Cuestiones relacionadas