En pytest, ¿para qué sirven los archivos conftest.py?

Recientemente descubrí pytest . Parece genial Sin embargo, creo que la documentación podría ser mejor.

Estoy tratando de entender para qué están destinados los archivos conftest.py .

En mi (actualmente pequeño) conjunto de pruebas tengo un archivo conftest.py en la raíz del proyecto. Lo uso para definir los accesorios que inyecto en mis pruebas.

Tengo dos preguntas:

  1. ¿Es este el uso correcto de conftest.py ? ¿Tiene otros usos?
  2. ¿Puedo tener más de un archivo conftest.py ? ¿Cuándo querría hacer eso? Se apreciarán ejemplos.

De manera más general, ¿cómo definiría el propósito y el uso correcto de los archivos conftest.py en un conjunto de pruebas py.test?

¿Es este el uso correcto de conftest.py?

Sí lo es. Los accesorios son un uso potencial y común de conftest.py . Los accesorios que definirá se compartirán entre todas las pruebas en su conjunto de pruebas. Sin embargo, la definición de los aparatos en la raíz conftest.py puede ser inútil y podría ralentizar las pruebas si no se utilizan dichos dispositivos en todas las pruebas.

¿Tiene otros usos?

Si lo hace

  • Fijaciones : defina las fijaciones para los datos estáticos utilizados por las pruebas. Se puede acceder a estos datos mediante todas las pruebas en la suite a menos que se especifique lo contrario. Esto podría ser tanto datos como ayudantes de módulos que se pasarán a todas las pruebas.

  • Carga de complementos externos : conftest.py se utiliza para importar complementos o módulos externos. Al definir la siguiente variable global, pytest cargará el módulo y lo pondrá a disposición para su prueba. Los complementos son generalmente archivos definidos en su proyecto u otros módulos que pueden ser necesarios en sus pruebas. También puede cargar un conjunto de complementos predefinidos como se explica aquí .

    pytest_plugins = "someapp.someplugin"

  • Enganches : puede especificar enganches como los métodos de configuración y desassembly y mucho más para mejorar sus pruebas. Para un conjunto de ganchos disponibles, lea aquí . Ejemplo:

     def pytest_runtest_setup(item): """ called before ``pytest_runtest_call(item). """ #do some stuff` 
  • Probar la ruta de la raíz : Esto es un poco de una característica oculta. Al definir conftest.py en su ruta raíz, tendrá pytest reconociendo sus módulos de aplicación sin especificar PYTHONPATH . En el fondo, py.test modifica su sys.path incluyendo todos los submódulos que se encuentran en la ruta raíz.

¿Puedo tener más de un archivo conftest.py?

Sí, puedes y se recomienda encarecidamente si la estructura de tu prueba es algo compleja. conftest.py archivos conftest.py tienen scope de directorio. Por lo tanto, crear accesorios y ayudantes específicos es una buena práctica.

¿Cuándo querría hacer eso? Se apreciarán ejemplos.

Varios casos podrían caber:

Creación de un conjunto de herramientas o ganchos para un grupo particular de pruebas.

root / mod / conftest.py

 def pytest_runtest_setup(item): print("I am mod") #do some stuff test root/mod2/test.py will NOT produce "I am mod" 

Cargando un conjunto de accesorios para algunas pruebas pero no para otras.

root / mod / conftest.py

 @pytest.fixture() def fixture(): return "some stuff" 

root / mod2 / conftest.py

 @pytest.fixture() def fixture(): return "some other stuff" 

root / mod2 / test.py

 def test(fixture): print(fixture) 

Imprimiré “algunas otras cosas”.

Anulación de ganchos heredados de la raíz conftest.py .

root / mod / conftest.py

 def pytest_runtest_setup(item): print("I am mod") #do some stuff 

root / conftest.py

 def pytest_runtest_setup(item): print("I am root") #do some stuff 

Al ejecutar cualquier prueba dentro de root/mod , solo se imprime “I am mod”.

Puedes leer más sobre conftest.py aquí .

EDITAR:

¿Qué sucede si necesito llamar a funciones de ayuda simples desde una serie de pruebas en diferentes módulos? ¿Estarán disponibles para mí si las coloco en conftest.py? ¿O debería simplemente ponerlos en un módulo helpers.py e importarlos y usarlos en mis módulos de prueba?

Puedes usar conftest.py para definir a tus ayudantes. Sin embargo, debe seguir la práctica común. Los ayudantes pueden usarse como accesorios al menos en pytest . Por ejemplo, en mis pruebas tengo un simulador de ayuda de redis que inyecto en mis pruebas de esta manera.

root / helper / redis / redis.py

 @pytest.fixture def mock_redis(): return MockRedis() 

root / tests / stuff / conftest.py

 pytest_plugin="helper.redis.redis" 

root / tests / stuff / test.py

 def test(mock_redis): print(mock_redis.get('stuff')) 

Este será un módulo de prueba que puede importar libremente en sus pruebas. TENGA redis.py CUENTA que potencialmente podría nombrar redis.py como conftest.py si su módulo redis contiene más pruebas. Sin embargo, esa práctica es desalentada debido a la ambigüedad.

Si desea utilizar conftest.py , simplemente puede poner ese ayudante en su raíz conftest.py e inyectarlo cuando sea necesario.

root / tests / conftest.py

 @pytest.fixture def mock_redis(): return MockRedis() 

root / tests / stuff / test.py

 def test(mock_redis): print(mock_redis.get(stuff)) 

Otra cosa que puedes hacer es escribir un complemento instalable. En ese caso, su ayudante puede escribirse en cualquier lugar, pero debe definir un punto de entrada que se instalará en su y en otros posibles marcos de prueba. Ver esto

Si no desea utilizar accesorios, puede, por supuesto, definir un ayudante simple y simplemente usar la importación antigua simple donde sea necesaria.

root / tests / helper / redis.py

 class MockRedis(): # stuff 

root / tests / stuff / test.py

 from helper.redis import MockRedis def test(): print(MockRedis().get(stuff)) 

Sin embargo, aquí es posible que tenga problemas con la ruta, ya que el módulo no se encuentra en una carpeta secundaria de la prueba. Debería poder superar esto (no probado) agregando un __init__.py a su ayudante

root / tests / helper / __ init__.py

 from .redis import MockRedis 

O simplemente agregando el módulo de ayuda a su PYTHONPATH .

En un sentido amplio, conftest.py es un complemento local por directorio. Aquí usted define ganchos y accesorios específicos del directorio. En mi caso, tengo un directorio raíz que contiene directorios de pruebas específicos del proyecto. Alguna magia común está estacionada en ‘root’ conftest.py. Proyecto específico – en sus propios. No puedo ver nada malo en almacenar dispositivos en conftest.py a menos que no se utilicen ampliamente (en ese caso, prefiero definirlos en los archivos de prueba directamente)

Utilizo el archivo conftest.py para definir los dispositivos que conftest.py en mis pruebas, ¿es este el uso correcto de conftest.py ?

, un dispositivo se suele utilizar para preparar los datos para múltiples pruebas.

¿Tiene otros usos?

, un accesorio es una función que está ejecutada por pytest antes, y algunas veces después, de las funciones de prueba reales. El código en el aparato puede hacer lo que quieras. Por ejemplo, se puede usar un dispositivo para obtener un conjunto de datos para que funcionen las pruebas, o también se puede usar un dispositivo para obtener un sistema en un estado conocido antes de ejecutar una prueba.

¿Puedo tener más de un archivo conftest.py ? ¿Cuándo querría hacer eso?

Primero, es posible poner aparatos en archivos de prueba individuales. Sin embargo, para compartir accesorios entre varios archivos de prueba, debe usar un archivo conftest.py un lugar central para todas las pruebas. Los accesorios pueden ser compartidos por cualquier prueba. Se pueden colocar en archivos de prueba individuales si desea que el dispositivo solo sea utilizado por las pruebas en ese archivo.

Segundo, , puede tener otros archivos conftest.py en los subdirectorios del directorio de pruebas superior. Si lo hace, los dispositivos definidos en estos archivos conftest.py nivel conftest.py estarán disponibles para las pruebas en ese directorio y subdirectorios.

Finalmente, colocar los accesorios en el archivo conftest.py en la raíz de prueba los pondrá a disposición en todos los archivos de prueba.