Defina un aparato pytest que proporcione múltiples argumentos para probar la función

Con pytest, puedo definir un accesorio así:

@pytest.fixture def foo(): return "blah" 

Y utilízalo en una prueba así:

 def test_blah(foo): assert foo == "blah" 

Eso es todo muy bien. Pero lo que quiero hacer es definir una única función de dispositivo que se “expanda” para proporcionar múltiples argumentos a una función de prueba. Algo como esto:

 @pytest.multifixture("foo,bar") def foobar(): return "blah", "whatever" def test_stuff(foo, bar): assert foo == "blah" and bar == "whatever" 

Quiero definir los dos objetos foo y bar juntos (no como aparatos separados) porque están relacionados de alguna manera. Es posible que a veces también quiera definir un accesorio que dependa de otro, pero que el segundo accesorio incorpore el resultado del primero y lo devuelva junto con su propia adición:

 @pytest.fixture def foo(): return "blah" @pytest.multifixture("foo,bar") def foobar(): f = foo() return f, some_info_related_to(f) 

Este ejemplo puede parecer tonto, pero en algunos casos foo es algo así como un objeto de solicitud, y el objeto de bar debe estar vinculado a ese mismo objeto de solicitud. (Es decir, no puedo definir foo y bar como elementos independientes porque necesito que ambos se deriven de una sola solicitud).

En esencia, lo que quiero hacer es desacoplar el nombre de la función del dispositivo del nombre del argumento de la función de prueba, de modo que pueda definir un dispositivo que es “activado” por un conjunto particular de nombres de argumentos en una firma de función de prueba , no solo un único argumento cuyo nombre es el mismo que el de la función del dispositivo.

Por supuesto, siempre puedo devolver una tupla como resultado del accesorio y luego descomprimirlo dentro de la función de prueba. Pero dado que pytest proporciona varios trucos mágicos para hacer coincidir automáticamente los nombres con los argumentos, parece que no es impensable que también pueda manejar esto mágicamente. ¿Es tal cosa posible con pytest?

nota: esta solución no funciona si su dispositivo depende de otros dispositivos con parámetros

No sé realmente si hay alguna solución predeterminada en el paquete pytest, pero puede hacer una personalizada:

 import pytest from _pytest.mark import MarkInfo def pytest_generate_tests(metafunc): test_func = metafunc.function if 'use_multifixture' in [name for name, ob in vars(test_func).items() if isinstance(ob, MarkInfo)]: result, func = test_func.use_multifixture.args params_names = result.split(',') params_values = list(func()) metafunc.parametrize(params_names, [params_values]) def foobar(): return "blah", "whatever" @pytest.mark.use_multifixture("foo,bar", foobar) def test_stuff(foo, bar): assert foo == "blah" and bar == "whatever" def test_stuff2(): assert 'blah' == "blah" 

Así que definimos la metafunción pytest_generate_tests. Esta función

  1. comprueba si la marca de multifixtura está en la prueba
  2. si la marca está activada, toma los nombres de las variables “foo, bar” y fucntion foobar que se ejecutarán en la generación

    @ pytest.mark.multifixture (“foo, bar”, foobar)