2011-07-11 6 views
29

Estoy escribiendo algunos casos de prueba para mi aplicación usando Python's unittest. Ahora necesito comparar una lista de objetos con una lista de otros objetos para verificar si los objetos de la primera lista son los que estoy esperando.Cómo escribir un método `.assertFoo()` personalizado en Python?

¿Cómo puedo escribir un método personalizado .assertFoo()? ¿Qué debería hacer? ¿Debería plantear una excepción en caso de error? Si es así, ¿qué excepción? ¿Y cómo pasar el mensaje de error? ¿Debería el mensaje de error ser una cadena unicode o una cadena de bytes?

Desafortunadamente, el official documentation no explica cómo escribir métodos de aserción personalizados.

Si necesita un ejemplo del mundo real para esto, continúe leyendo.


El código que estoy escribiendo es algo como esto:

def assert_object_list(self, objs, expected): 
    for index, (item, values) in enumerate(zip(objs, expected)): 
     self.assertEqual(
      item.foo, values[0], 
      'Item {0}: {1} != {2}'.format(index, item.foo, values[0]) 
     ) 
     self.assertEqual(
      item.bar, values[1], 
      'Item {0}: {1} != {2}'.format(index, item.bar, values[1]) 
     ) 

def test_foobar(self): 
    objs = [...] # Some processing here 
    expected = [ 
     # Expected values for ".foo" and ".bar" for each object 
     (1, 'something'), 
     (2, 'nothing'), 
    ] 
    self.assert_object_list(objs, expected) 

Este enfoque hace que sea extremadamente fácil de describir los valores esperados de cada objeto en una forma muy compacta, y sin necesidad de realidad crear objetos completos

Sin embargo ... Cuando un objeto falla la aserción, no se comparan más objetos, y esto hace que la depuración sea un poco más difícil. Me gustaría escribir un método personalizado que compare incondicionalmente todos los objetos, y luego mostraría todos los objetos que fallaron, en lugar de solo el primero.

Respuesta

27

Uso la herencia múltiple en estos casos. Por ejemplo:

Primero. Defino una clase con métodos que incorporaré.

import os 

class CustomAssertions: 
    def assertFileExists(self, path): 
     if not os.path.lexists(path): 
      raise AssertionError('File not exists in path "' + path + '".') 

Ahora definir una clase que hereda de unittest.TestCase y CustomAssertion

import unittest 

class MyTest(unittest.TestCase, CustomAssertions): 
    def test_file_exists(self): 
     self.assertFileExists('any/file/path') 

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

Buen enfoque alternativo para la creación de subclases: esto fue útil. –

+7

Este enfoque también se llama [mixin] (https://en.wikipedia.org/wiki/Mixin#In_Python). –

+0

@ DenilsonSáMaia - ¿Está bien hacer que una declaración personalizada devuelva algo? –

17

Debe crear su propia clase TestCase, derivada de unittest.TestCase. Luego, coloque su método de afirmación personalizada en esa clase de caso de prueba. Si tu prueba falla, levanta un AssertionError. Su mensaje debe ser una cadena. Si desea probar todos los objetos de la lista en lugar de detenerse en un error, recopile una lista de índices anómalos y, después del ciclo sobre todos los objetos, cree un mensaje afirmativo que resuma sus hallazgos.

+1

¿Hay alguna diferencia en el aumento un 'AssertionError' y cualquier otra' Exception' (con respecto a los asserts personalizados y 'unittest') – hiwaylon

0

Sólo un ejemplo para resumir con una comparaison numpy unittest

import numpy as np 
class CustomTestCase(unittest.TestCase): 
    def npAssertAlmostEqual(self, first, second, rtol=1e-06, atol=1e-08): 
     np.testing.assert_allclose(first, second, rtol=rtol, atol=atol) 


class TestVector(CustomTestCase): 
    def testFunction(self): 
     vx = np.random.rand(size) 
     vy = np.random.rand(size) 
     self.npAssertAlmostEqual(vx, vy) 
Cuestiones relacionadas