2010-08-31 12 views
9

Tengo un grupo de casos de prueba en los que todos deben hacer exactamente la misma prueba, en la línea de "¿El método x devuelve el nombre de un archivo existente?"¿Cómo puedo agregar un método de prueba a un grupo de clases derivadas de Django TestCase?

Pensé que la mejor manera de hacerlo sería una clase base derivada de TestCase que todos comparten, y simplemente agregue la prueba a esa clase. Desafortunadamente, el marco de prueba todavía intenta ejecutar la prueba para la clase base, donde no tiene sentido.

class SharedTest(TestCase): 
    def x(self): 
     ...do test... 

class OneTestCase(SharedTest): 
    ...my tests are performed, and 'SharedTest.x()'... 

me trataron de cortar en un cheque para simplemente omitir la prueba si se llama a un objeto de la clase base en lugar de una clase derivada de esta manera:

class SharedTest(TestCase): 
     def x(self): 
      if type(self) != type(SharedTest()): 
       ...do test... 
      else: 
       pass 

pero consiguió este error:

ValueError: no such test method in <class 'tests.SharedTest'>: runTest 

En primer lugar, me gustaría cualquier sugerencia elegante para hacer esto. En segundo lugar, aunque realmente no quiero usar el hack de tipo(), me gustaría entender por qué no está funcionando.

+0

@jivanamara: Hay una manera de evitar que se cuente el método de prueba de superclase _and_ para escribir el método de prueba sin la comprobación 'if getattr (...)'. Ver la segunda actualización de mi respuesta. –

Respuesta

1

Me enfrenté a un problema similar. No pude evitar que se ejecutara el método de prueba en la clase base, pero me aseguré de que no ejerciera ningún código real. Hice esto comprobando un atributo y volviendo inmediatamente si estaba configurado. Este atributo solo se estableció para la clase Base y, por lo tanto, las pruebas se ejecutaron en cualquier otro lugar excepto la clase base.

class SharedTest(TestCase): 
    def setUp(self): 
     self.do_not_run = True 

    def test_foo(self): 
     if getattr(self, 'do_not_run', False): 
      return 
     # Rest of the test body. 

class OneTestCase(SharedTest): 
    def setUp(self): 
     super(OneTestCase, self).setUp() 
     self.do_not_run = False 

Esto es un poco hackeo. Hay probablemente una mejor manera de hacer esto pero no estoy seguro de cómo .

actualización

Como sdolan says mixin es la manera correcta. ¿Por qué no lo vi antes?

Actualización 2

(Después de leer los comentarios) Sería bueno si (1) el método de la superclase pudo evitar el hacker if getattr(self, 'do_not_run', False): cheque; (2) si el número de pruebas se contaron con precisión.

Hay una forma posible de hacerlo. Django recoge y ejecuta todas las clases de prueba en tests, ya sea tests.py o un paquete con ese nombre. Si la prueba de la superclase se declara fuera de el módulo de pruebas, entonces esto no sucederá. Todavía puede ser heredado por clases de prueba. Por ejemplo, SharedTest puede ubicarse en app.utils y luego ser utilizado por los casos de prueba. Esta sería una versión más limpia de la solución anterior.

# module app.utils.test 
class SharedTest(TestCase): 
    def test_foo(self): 
     # Rest of the test body. 

# module app.tests 
from app.utils import test 
class OneTestCase(test.SharedTest): 
    ... 
+0

Porque no preguntó al respecto en SO :) – sdolan

+0

Esto es lo que codifiqué después de hacer la pregunta. Es un truco, pero a pilyl le gusta y no veo que sea significativamente peor que mixin. El único inconveniente es que agrega una prueba inexistente al conteo de pruebas ... no algo que me mantendrá despierto por la noche. – JivanAmara

+0

Dado que no estoy muy familiarizado con la filosofía de mixins, rebotó esto de un amigo y él confirmó mi vacilación; diciendo que los mixins se supone que son autónomos. Voy con esta solución ya que la solución de mixina hace que la mixina dependa de las clases que la usarán. – JivanAmara

22

Se puede usar un mixin tomando ventaja de que el corredor de prueba sólo se ejecuta pruebas que heredan de unittest.TestCase Por ejemplo (que TestCase hereda de Django partir.):

class SharedTestMixin(object): 
    # This class will not be executed by the test runner (it inherits from object, not unittest.TestCase. 
    # If it did, assertEquals would fail , as it is not a method that exists in `object` 
    def test_common(self): 
     self.assertEquals(1, 1) 


class TestOne(TestCase, SharedTestMixin): 
    def test_something(self): 
     pass 

    # test_common is also run 

class TestTwo(TestCase, SharedTestMixin): 
    def test_another_thing(self): 
     pass 

    # test_common is also run 

Para obtener más información sobre por qué esto funciona hacer una búsqueda de orden de resolución de método python y herencia múltiple.

+0

+1. Esta es la forma limpia de hacerlo. –

+0

Gracias por su respuesta, Empecé de esta manera, y no me gustó que tuviera una clase que llamaba a métodos que no tenía. Pylint también ladra por esto, y uso mucho la pildora. – JivanAmara

+0

@jivanamara: No necesita llamar 'test_common' dentro de sus clases de prueba' TestOne' y 'TestTwo'. Está "mezclado", ya que era parte de la clase a través de herencia múltiple. – sdolan

Cuestiones relacionadas