Pytest: Cómo asegurarse de que un determinado dispositivo se llame primero

Tengo algunos datos en un a_file que necesito para parametrizar mi dispositivo. Por lo tanto, escribí una función auxiliar que devuelve una a_list llena con los datos del archivo. Ahora puedo parametrizar fácilmente mi dispositivo a través de @pytest.fixture(params=a_list) . Parece directo, ¿verdad?

El problema aquí es que a_file es generado por otro dispositivo y parece que pytest llama al ayudante que depende de ese archivo antes de que el archivo realmente cree el archivo. Debido a ese comportamiento, se FileNotFoundError un FileNotFoundError .

Mi código se ve así:

 def helper_returning_list_from_a_file(): with open("a_file") as a_file: a_list = a_file.readlines() return a_list @pytest.fixture(scope="session") def create_file_fixture(depends_on_other_fixtures): # create "a_file" here @pytest.fixture(params=helper_returning_list_from_a_file()) def a_fixture_which_is_parametrized_with_data_from_a_file(request): return request.param def test_which_uses(a_fixture_which_is_parametrized_with_data_from_a_file): assert False 

Adición: create_file_fixture debe ser un accesorio y no se puede transformar en una función normal porque depende de otros accesorios.


Lo que ya probé

La solución obvia es asegurarse de que el archivo se cree antes de que se ejecute la función auxiliar que necesita el archivo.

Por lo tanto, yo

  • agregó una dependencia para create_file_fixture al dispositivo que debería parametrizarse de esta manera:

     @pytest.fixture(params=helper_returning_list_from_a_file()) def a_fixture_which_is_parametrized_with_data_from_a_file(create_file_fixture, request): return request.param 
  • agregó la bandera de autouse al aparato que crea el archivo así:

     @pytest.fixture(scope="session", autouse=True) def create_file_fixture: # create "a_file" here 

pero pytest todavía llama a las funciones de ayuda primero, lo que resulta en el mismo error descrito anteriormente.


Pregunta

¿Cómo puedo asegurarme de que el create_file_fixture se ejecute primero?


Solución posible

Creo que una posible solución sería transformar la función de ayuda en un dispositivo también. Así que fácilmente podría agregar la dependencia que dictaría a pytest en qué orden se deben ejecutar los aparatos. Esto se vería así:

 @pytest.fixture() def fixture_returning_list_from_a_file(create_file_fixture): with open("a_file") as a_file: a_list = a_file.readlines() return a_list 

Esto resolvería mi problema de que el archivo no existe, pero esto tampoco me funciona porque me lleva a otro problema que describí aquí: parametrizar una prueba con una lista devuelta desde un dispositivo .

El error no es causado por pytest como tal. Esto se debe al hecho de que la función auxiliar se llama cuando el intérprete de Python carga el módulo, nominalmente antes de que llegue a pytest.

Desafortunadamente, no puede obtener más de un valor de un accesorio, y no puede parametrizar sobre un generador perezoso. La razón es que el gráfico completo debe calcularse antes de ejecutar cualquier dispositivo o prueba, lo que significa conocer todos los parámetros por adelantado, como se explica en esta solicitud de función fallida . El comentario de @ Hoefling sugiere una forma de evitar esto. Yo sugeriría una forma que es probablemente menos tónica, pero debería funcionar a pesar de todo.

Para asegurarse de que su archivo se cree por adelantado y de que toda la lista esté disponible para la parametrización, no lo convierta en un elemento fijo: simplemente ejecútelo como parte de su código de carga del módulo y haga de la lista un atributo de módulo. Esto no evitará que lo uses en otro lugar. Si varios módulos de prueba utilizan la misma lista, puede colocarlo en un módulo independiente que no sea de prueba e importarlo a las pruebas que lo necesiten.

 def create_file_function(): # create "a_file" here return 'a_file' def helper_returning_list_from_a_file(): with open(create_file_function()) as a_file: a_list = a_file.readlines() return a_list a_list = helper_returning_list_from_a_file() @pytest.fixture(params=a_list) def a_fixture_which_is_parametrized_with_data_from_a_file(request): return request.param def test_which_uses(a_fixture_which_is_parametrized_with_data_from_a_file): assert False 

Creo que es un poco más elegante / configurable que create_file_function devuelva el nombre del archivo.

Dado a_file que se parece a:

 ABC DEF 

La salida de pytest -v ve así:

 ============================= test session starts ============================== platform linux -- Python 3.6.4, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- /... cachedir: .pytest_cache rootdir: /..., inifile: plugins: remotedata-0.2.0, pep8-1.0.6, openfiles-0.2.0, doctestplus-0.1.2, arraydiff-0.2 collected 2 items 52765085.py::test_which_uses[ABC\n] PASSED [ 50%] 52765085.py::test_which_uses[DEF] PASSED [100%] =========================== 2 passed in 0.01 seconds ===========================