Quiero poder devolver un valor de un dispositivo a múltiples pruebas / clases de prueba, pero el valor que se pasa es una función.

Aquí está mi código:

import pytest

@pytest.fixture()
def user_setup():
    user = {
        'name': 'chad',
        'id': 1
    }
    return user

@pytest.mark.usefixtures('user_setup')
class TestThings:
    def test_user(self):
        assert user_setup['name'] == 'chad'

La salida es:

=================================== FAILURES ===================================
_____________________________ TestThings.test_user _____________________________

self = <tests.test_again.TestThings instance at 0x10aed6998>

    def test_user(self):
>       assert user_setup['name'] == 'chad'
E       TypeError: 'function' object has no attribute '__getitem__'

tests/test_again.py:14: TypeError
=========================== 1 failed in 0.02 seconds ===========================

Pero si reescribo mi prueba para que no use el decorador usefixtures, funciona como se esperaba:

def test_user(user_setup):
    assert user_setup['name'] == 'chad'

¿Alguna idea de por qué no funciona cuando intento usar el método decorador?

7
Cass 29 ago. 2014 a las 02:55

2 respuestas

La mejor respuesta

Cuando usa el marcador @pytest.mark.usefixtures aún necesita proporcionar un argumento de entrada con un nombre similar si desea que ese dispositivo se inyecte en su función de prueba.

Como se describe en los documentos de py.test para accesorios:

Posteriormente se puede hacer referencia al nombre de la función de dispositivo para provocar su invocación antes de ejecutar las pruebas ... Las funciones de prueba pueden usar directamente los nombres de dispositivo como argumentos de entrada, en cuyo caso se inyectará la instancia de dispositivo devuelta por la función de dispositivo.

Entonces, solo usando el decorador @pytest.mark.usefixtures solo invocará la función. Proporcionar un argumento de entrada le dará el resultado de esa función.

Realmente solo necesita usar @pytest.mark.usefixtures cuando desea invocar un dispositivo fijo pero no quiere tenerlo como argumento de entrada para su prueba. Como se describe en el documentos de py.test .

La razón por la que obtiene una excepción que habla de que user_setup es una función es porque dentro de su función test_user el nombre user_setup en realidad se refiere a la función que definió anteriormente en el archivo. Para que su código funcione como espera, necesitará agregar un argumento a la función test_user:

@pytest.mark.usefixtures('user_setup')
class TestThings:
    def test_user(self, user_setup):
        assert user_setup['name'] == 'chad'

Ahora, desde la perspectiva de la función test_user, el nombre user_setup se referirá al argumento de la función, que será el valor devuelto del dispositivo inyectado por py.test.

Pero realmente no necesitas usar el decorador @pytest.mark.usefixtures en absoluto.

16
Jeremy Allen 29 ago. 2014 a las 00:45

En ambos casos, en el ámbito global user_setup se refiere a la función. La diferencia es que, en su versión no fija, está creando un parámetro con el mismo nombre, que es una receta clásica para la confusión.

En esa versión no fija, dentro del alcance de test_user, su identificador user_setup se refiere a lo que sea que esté pasando, NO a la función en el alcance global.

Creo que probablemente te refieres a estar llamando user_setup y suscribiendo el resultado como

assert user_setup()['name'] == 'chad'
-2
user1541898 28 ago. 2014 a las 23:38