test - ¿A dónde van las pruebas unitarias de Python?
unit test python (17)
Si está escribiendo una biblioteca o una aplicación, ¿a dónde van los archivos de prueba de la unidad?
Es bueno separar los archivos de prueba del código principal de la aplicación, pero es incómodo colocarlos en un subdirectorio de "pruebas" dentro del directorio raíz de la aplicación, ya que dificulta la importación de los módulos que probará.
¿Hay una mejor práctica aquí?
Sólo 1 archivo de prueba
Si no tiene muchos archivos de prueba, ponerlo en un directorio de nivel superior es bueno (creo que es una forma pythonic (recomendada)):
module/
lib/
__init__.py
module.py
test.py
Muchos archivos de prueba
Si tiene muchos archivos de prueba, póngalo en una carpeta de tests
:
module/
lib/
__init__.py
module.py
tests/
test_module.py
test_module2.py
pero si coloca las pruebas en la carpeta de tests
, la prueba no puede import ..lib
en CLI porque __main__
no puede importar módulos relativos, así que en su lugar podemos usar nose , o podemos agregar un directorio principal a la ruta de importación de python, y para eso crearé un
env.py
import sys
import os
# append module root directory to sys.path
sys.path.append(
os.path.dirname(
os.path.dirname(
os.path.abspath(__file__)
)
)
)
en
module/
tests/
test_module.py
env.py
e import env
antes de prueba módulo de importación
test_module.py
import unittest
# append parent directory to import path
import env
# now we can import the lib module
from lib import module
if __name__ == ''__main__'':
unittest.main()
Al escribir un paquete llamado "foo", pondré las pruebas unitarias en un paquete separado "foo_test". Los módulos y subpaquetes tendrán el mismo nombre que el módulo del paquete SUT. Por ejemplo, las pruebas para un módulo foo.xy se encuentran en foo_test.xy Los archivos __init__.py de cada paquete de prueba contienen un conjunto de pruebas AllTests que incluye todas las suites de prueba del paquete. setuptools proporciona una manera conveniente de especificar el paquete de prueba principal, de modo que después de "python setup.py develop" puedes usar "python setup.py test" o "python setup.py test -s foo_test.x.SomeTestSuite" Sólo una suite específica.
Cómo lo hago...
Estructura de la carpeta:
project/
src/
code.py
tests/
setup.py
Setup.py apunta a src / como la ubicación que contiene los módulos de mis proyectos, luego ejecuto:
setup.py develop
Lo que agrega mi proyecto en los paquetes de sitio, apuntando a mi copia de trabajo. Para ejecutar mis pruebas utilizo:
setup.py tests
Usando cualquier corredor de prueba que haya configurado.
De vez en cuando me encuentro revisando el tema de la ubicación de la prueba, y cada vez que la mayoría recomienda una estructura de carpetas separada junto al código de la biblioteca, pero encuentro que cada vez los argumentos son los mismos y no son tan convincentes. Termino poniendo mis módulos de prueba en algún lugar al lado de los módulos centrales.
La principal razón para hacer esto es: refactorización .
Cuando muevo cosas, quiero que los módulos de prueba se muevan con el código; es fácil perder las pruebas si están en un árbol separado. Seamos honestos, tarde o temprano terminará con una estructura de carpetas totalmente diferente, como django , flask y muchos otros. Lo que está bien si no te importa.
La pregunta principal que debes hacerte es esta:
Estoy escribiendo:
- a) biblioteca reutilizable o
- b) ¿Construir un proyecto que agrupar algunos módulos semi-separados?
Si un
Una carpeta separada y el esfuerzo adicional para mantener su estructura pueden ser más adecuados. Nadie se quejará de que sus pruebas se hayan implementado en producción .
Pero también es tan fácil excluir la distribución de las pruebas cuando se mezclan con las carpetas centrales; pon esto en el setup.py :
find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"])
Si b:
Es posible que desee, como todos nosotros lo hacemos, que esté escribiendo bibliotecas reutilizables, pero la mayor parte del tiempo su vida está vinculada a la vida del proyecto. La capacidad de mantener fácilmente su proyecto debe ser una prioridad.
Luego, si hizo un buen trabajo y su módulo es un buen ajuste para otro proyecto, probablemente se copiará, no se bifurcará o convertirá en una biblioteca separada, en este nuevo proyecto, y se moverán las pruebas que se encuentran a su lado en la misma estructura de carpetas. es fácil en comparación con la pesca de pruebas en un lío en el que se había convertido una carpeta de prueba separada. (Puedes argumentar que no debería ser un desastre en primer lugar, pero seamos realistas aquí).
Por lo tanto, la elección sigue siendo suya, pero yo diría que con las pruebas mixtas se logran todas las mismas cosas que con una carpeta separada, pero con menos esfuerzo para mantener las cosas ordenadas.
Desde mi experiencia en el desarrollo de marcos de prueba en Python, sugeriría poner las pruebas unitarias de Python en un directorio separado. Mantener una estructura de directorios simétrica. Esto sería útil para empaquetar solo las bibliotecas centrales y no para empaquetar las pruebas unitarias. A continuación se implementa a través de un diagrama esquemático.
<Main Package>
/ /
/ /
lib tests
/ /
[module1.py, module2.py, [ut_module1.py, ut_module2.py,
module3.py module4.py, ut_module3.py, ut_module.py]
__init__.py]
De esta manera, al empaquetar estas bibliotecas utilizando un rpm, solo puede empaquetar los módulos de la biblioteca principal (solo). Esto ayuda a la mantenibilidad particularmente en un entorno ágil.
En C #, generalmente he separado las pruebas en un ensamblaje separado.
En Python, hasta ahora, he tendido a escribir doctests, donde la prueba está en la cadena de documentación de una función, o ponerlos en el bloque if __name__ == "__main__"
en la parte inferior del módulo.
No creo que haya una "mejor práctica" establecida.
Pongo mis pruebas en otro directorio fuera del código de la aplicación. Luego agrego el directorio principal de la aplicación a sys.path (permitiéndole importar los módulos desde cualquier lugar) en mi script del corredor de prueba (que también hace otras cosas) antes de ejecutar todas las pruebas. De esta manera nunca tengo que eliminar el directorio de pruebas del código principal cuando lo libero, lo que me ahorra tiempo y esfuerzo, aunque sea una cantidad tan pequeña.
Prefiero el directorio de pruebas de nivel superior. Esto significa que las importaciones se vuelven un poco más difíciles. Para eso tengo dos soluciones:
- Utilice setuptools. Luego puede pasar
test_suite=''tests.runalltests.suite''
asetup()
, y puede ejecutar las pruebas simplemente:python setup.py test
- Establezca PYTHONPATH al ejecutar las pruebas:
PYTHONPATH=. python tests/runalltests.py
PYTHONPATH=. python tests/runalltests.py
Así es como el código de M2Crypto admite esas cosas:
- http://svn.osafoundation.org/m2crypto/trunk/setup.py
- http://svn.osafoundation.org/m2crypto/trunk/tests/alltests.py
Si prefiere realizar pruebas con pruebas de detección, puede que necesite hacer algo un poco diferente.
Recientemente comencé a programar en Python, por lo que aún no he tenido la oportunidad de descubrir las mejores prácticas. Pero, he escrito un módulo que va y encuentra todas las pruebas y las ejecuta.
Así que tengo:
app/ appfile.py test/ appfileTest.py
Tendré que ver cómo va a medida que avance hacia proyectos más grandes.
Si las pruebas son simples, simplemente colóquelas en la cadena de documentación; la mayoría de los marcos de prueba para Python podrán usar eso:
>>> import module
>>> module.method(''test'')
''testresult''
Para otras pruebas más complicadas, las pondría en ../tests/test_module.py
o en tests/test_module.py
.
También tiendo a poner mis pruebas unitarias en el archivo, como señala Jeremy Cantrell arriba, aunque tiendo a no poner la función de prueba en el cuerpo principal, sino a poner todo en una
if __name__ == ''__main__'':
do tests...
bloquear. Esto termina agregando documentación al archivo como ''código de ejemplo'' sobre cómo usar el archivo python que está probando.
Debo agregar, tiendo a escribir módulos / clases muy ajustados. Si sus módulos requieren un gran número de pruebas, puede ponerlas en otra, pero aún así, yo agregaría:
if __name__ == ''__main__'':
import tests.thisModule
tests.thisModule.runtests
Esto permite que cualquiera que lea su código fuente sepa dónde buscar el código de prueba.
Te recomiendo que revises algunos proyectos principales de Python en GitHub y obtengas algunas ideas.
Cuando su código crezca y agregue más bibliotecas, es mejor crear una carpeta de prueba en el mismo directorio que tiene setup.py y reflejar la estructura de directorios de su proyecto para cada tipo de prueba (test de unidad, integración, ...)
Por ejemplo, si tiene una estructura de directorios como:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
setup.py
Después de agregar la carpeta de prueba, tendrá una estructura de directorio como:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
test/
unit/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
integration/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
setup.py
Muchos paquetes de Python correctamente escritos utilizan la misma estructura. Un muy buen ejemplo es el paquete Boto. Compruebe https://github.com/boto/boto
Tuvimos la misma pregunta al escribir Pythoscope ( http://pythoscope.org ), que genera pruebas unitarias para los programas Python. Encuestamos a las personas en la lista de pruebas en python antes de elegir un directorio, había muchas opiniones diferentes. Al final, elegimos colocar un directorio de "pruebas" en el mismo directorio que el código fuente. En ese directorio generamos un archivo de prueba para cada módulo en el directorio principal.
Una práctica común es colocar el directorio de pruebas en el mismo directorio principal que su módulo / paquete. Entonces, si su módulo se llamara foo.py, el diseño de su directorio se vería así:
parent_dir/
foo.py
tests/
Por supuesto que no hay una sola manera de hacerlo. También puede crear un subdirectorio de pruebas e importar el módulo utilizando la importación absoluta .
Donde sea que ponga sus pruebas, le recomendaría que use la nose para ejecutarlas. Búsqueda de la nose través de sus directorios para las pruebas. De esta manera, puedes poner pruebas donde sea que tengan más sentido organizacionalmente.
Usamos
app / src / code.py
app / testing / code_test.py
app / docs / ..
En cada archivo de prueba insertamos "../src/" en sys.path. No es la mejor solución pero funciona. Creo que sería genial si alguien se presentara con algo como maven in java que te ofrece convenciones estándar que simplemente funcionan, sin importar en qué proyecto trabajes.
Utilizo un directorio de tests/
y luego importo los módulos principales de la aplicación usando importaciones relativas. Entonces, en MyApp / tests / foo.py, puede haber:
from .. import foo
para importar el módulo MyApp.foo
.
Para un archivo module.py
, la prueba de la unidad normalmente debería llamarse test_module.py
, siguiendo las convenciones de nomenclatura de Pythonic.
Hay varios lugares comúnmente aceptados para poner test_module.py
:
- En el mismo directorio que
module.py
. - En
../tests/test_module.py
(en el mismo nivel que el directorio de códigos). - En
tests/test_module.py
(un nivel bajo el directorio de códigos).
Prefiero el # 1 por su simplicidad de encontrar las pruebas e importarlas. Cualquier sistema de compilación que esté utilizando se puede configurar fácilmente para ejecutar archivos que comiencen con test_
. En realidad, el patrón de prueba de unittest
predeterminado utilizado para el descubrimiento de test*.py
es test*.py
.