Ejecute la configuración solo una vez para un conjunto de pruebas automatizadas

81

Mi versión de Python es 2.6.

Me gustaría ejecutar el método de configuración de prueba solo una vez, ya que allí hago cosas que son necesarias para todas las pruebas.

Mi idea era crear una variable booleana que se establecería en 'verdadera' después de la primera ejecución y luego deshabilitar más de una llamada al método de configuración.

class mySelTest(unittest.TestCase):
    setup_done = False

    def setUp(self):
        print str(self.setup_done)
            
        if self.setup_done:
            return
        self.setup_done = True
        print str(self.setup_done)

La salida:

False

True

--- Test 1 ---

False

True

--- Test 2 ---

¿Por qué esto no funciona? ¿Yo me perdí algo?

Kesandal
fuente
6
Unittest crea instancias separadas para cada prueba
David Robinson
2
No hagas esto. Implemente algún otro mecanismo. Pero no intentes cambiar el significado de setUp.
David Heffernan
Posible duplicado de Unittest setUp / tearDown para varias pruebas
Stevoisiak

Respuestas:

113

Puede utilizar setUpClasspara definir métodos que solo se ejecutan una vez por suite de prueba.

Daniel Roseman
fuente
Gracias por su respuesta. Como estoy usando Python 2.6.6, setUpClass no está disponible.
Kesandal
2
@JohnM .: Puede descargar el paquete de backport unittest2 y obtener todas las cosas nuevas en su python-dist anterior.
Macke
La pregunta trata sobre Python 2, pero como la respuesta también es válida para Python 3, cambié la URL ya que Python 2 está obsoleto.
CharlesB
64

La respuesta de Daniel es correcta, pero aquí es un ejemplo a evitar algunos errores comunes que he encontrado, como no llamar super()en setUpClass()cuando TestCasees una subclase de unittest.TestCase(como en django.testo falcon.testing).

La documentación de setUpClass()no menciona que debe llamar super()en tales casos. Obtendrá un error si no lo hace, como se ve en esta pregunta relacionada .

class SomeTest(TestCase):
    def setUp(self):
        self.user1 = UserProfile.objects.create_user(resource=SomeTest.the_resource)

    @classmethod
    def setUpClass(cls):
        """ get_some_resource() is slow, to avoid calling it for each test use setUpClass()
            and store the result as class variable
        """
        super(SomeTest, cls).setUpClass()
        cls.the_resource = get_some_resource()
Chemary
fuente
1
Tenga en cuenta que esto es relevante solo cuando TestCasees una subclase de unittest.TestCase.
EliadL
3

Si terminó aquí debido a la necesidad de cargar algunos datos para la prueba ... entonces, en la medida en que esté usando Django 1.9+, vaya a setUpTestData :

class MyTests(TestCase):

    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.foo = Foo.objects.create(bar="Test")

    def test1(self):
        self.assertEqual(self.foo.bar, 'Test') 
andilabs
fuente
2

No intente deduplicar las llamadas para configurar, solo llámelo una vez.

Por ejemplo:

class MyClass(object):
    ...

def _set_up():
    code to do one-time setup

_set_up()

Esto llamará a _set_up () cuando el módulo se cargue por primera vez. Lo he definido como una función a nivel de módulo, pero también podría convertirlo en un método de clase de MyClass.

Paul Hankin
fuente
2

Coloque todo el código que desee configurar una vez fuera de mySelTest.

setup_done = False

class mySelTest(unittest.TestCase):

    def setUp(self):
        print str(setup_done)

        if setup_done:
            return

        setup_done = True
        print str(setup_done)

Otra posibilidad es tener una clase Singleton en la que cree una instancia setUp(), que solo ejecutará el __new__código una vez y devolverá la instancia del objeto para el resto de las llamadas. Ver: ¿Existe una forma simple y elegante de definir singletons?

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                            cls, *args, **kwargs)
            # PUT YOUR SETUP ONCE CODE HERE!
            cls.setUpBool = True

        return cls._instance

class mySelTest(unittest.TestCase):

    def setUp(self):
        # The first call initializes singleton, ever additional call returns the instantiated reference.
        print(Singleton().setUpBool)

Sin embargo, tu forma también funciona.

NuclearPeon
fuente
2

setup_done es una variable de clase, no una variable de instancia.

Lo está haciendo referencia como una variable de instancia:

self.setup_done

Pero debe hacer referencia a ella como una variable de clase:

mySelTest.setup_done

Aquí está el código corregido:

class mySelTest(unittest.TestCase):
    setup_done = False

    def setUp(self):
        print str(mySelTest.setup_done)

        if mySelTest.setup_done:
            return
        mySelTest.setup_done = True
        print str(mySelTest.setup_done)
frijol jersey
fuente
1

Estoy usando Python 3 y descubrí que la clsreferencia también está disponible en el setupmétodo, por lo que funciona lo siguiente:

class TestThing(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.thing = Thing() # the `thing` is only instantiated once

  def setup(self):
    self.thing = cls.thing # ...but set on each test case instance

  def test_the_thing(self):
    self.assertTrue(self.thing is not None)
Greg Ross
fuente