seqio - read fasta python
¿Cómo ejecutar unittest discover de "python setup.py test"? (7)
Estoy intentando descubrir cómo hacer que python setup.py test
ejecute el equivalente de python -m unittest discover
. No quiero usar un script run_tests.py y no quiero usar ninguna herramienta de prueba externa (como nose
o py.test
). Está bien si la solución solo funciona en Python 2.7.
En setup.py
, creo que necesito agregar algo a los test_suite
y / o test_loader
en config, pero parece que no puedo encontrar una combinación que funcione correctamente:
config = {
''name'': name,
''version'': version,
''url'': url,
''test_suite'': ''???'',
''test_loader'': ''???'',
}
¿Es posible usar solo unittest
integrado en python 2.7?
FYI, mi estructura de proyecto se ve así:
project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
run_tests.py <- I want to delete this
setup.py
Actualización : Esto es posible con unittest2
pero quiero encontrar algo equivalente usando solo unittest
Desde https://pypi.python.org/pypi/unittest2
unittest2 incluye un recopilador de prueba compatible con herramientas de configuración muy básicas. Especifique test_suite = ''unittest2.collector'' en su setup.py. Esto inicia el descubrimiento de prueba con los parámetros predeterminados del directorio que contiene setup.py, por lo que quizás sea más útil como ejemplo (vea unittest2 / collector.py).
Por ahora, solo estoy usando un script llamado run_tests.py
, pero espero poder deshacerme de esto pasando a una solución que solo usa la python setup.py test
.
Aquí está el run_tests.py
que espero eliminar:
import unittest
if __name__ == ''__main__'':
# use the default shared TestLoader instance
test_loader = unittest.defaultTestLoader
# use the basic test runner that outputs to sys.stderr
test_runner = unittest.TextTestRunner()
# automatically discover all tests in the current dir of the form test*.py
# NOTE: only works for python 2.7 and later
test_suite = test_loader.discover(''.'')
# run the test suite
test_runner.run(test_suite)
Desde la creación y distribución de paquetes con SetupTools (énfasis mío):
Banco de pruebas
Una cadena que nombra una subclase unittest.TestCase (o un paquete o módulo que contiene uno o más de ellos, o un método de dicha subclase), o que nombra una función a la que se puede llamar sin argumentos y devuelve un unittest.TestSuite .
Por lo tanto, en setup.py
agregaría una función que devuelve TestSuite:
import unittest
def my_test_suite():
test_loader = unittest.TestLoader()
test_suite = test_loader.discover(''tests'', pattern=''test_*.py'')
return test_suite
Luego, debe especificar la setup
del comando de setup
siguiente manera:
setup(
...
test_suite=''setup.my_test_suite'',
...
)
El módulo de unittest
biblioteca estándar de Python admite el descubrimiento (en Python 2.7 y posterior, y Python 3.2 y posterior). Si puede asumir esas versiones mínimas, puede agregar el argumento de línea de comando de discover
comando unittest
.
Solo se necesita una pequeña modificación para setup.py
:
import setuptools.command.test
from setuptools import (find_packages, setup)
class TestCommand(setuptools.command.test.test):
""" Setuptools test command explicitly using test discovery. """
def _test_args(self):
yield ''discover''
for arg in super(TestCommand, self)._test_args():
yield arg
setup(
...
cmdclass={
''test'': TestCommand,
},
)
Esto no eliminará run_tests.py, pero lo hará funcionar con setuptools. Añadir:
class Loader(unittest.TestLoader):
def loadTestsFromNames(self, names, _=None):
return self.discover(names[0])
Luego en setup.py: (supongo que estás haciendo algo como setup(**config)
)
config = {
...
''test_loader'': ''run_tests:Loader'',
''test_suite'': ''.'', # your start_dir for discover()
}
El único inconveniente que veo es que está doblando la semántica de loadTestsFromNames
, pero el comando de prueba setuptools es el único consumidor y lo llama de una manera específica .
No necesitas config para que esto funcione. Básicamente, hay dos formas principales de hacerlo:
La manera rápida
Cambie el nombre de su test_module.py
a module_test.py
(básicamente agregue _test
como un sufijo para las pruebas de un módulo en particular), y python lo encontrará automáticamente. Solo asegúrate de agregar esto a setup.py
:
from setuptools import setup, find_packages
setup(
...
test_suite = ''tests'',
...
)
El largo camino
A continuación, le mostramos cómo hacerlo con su estructura de directorio actual:
project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
run_tests.py <- I want to delete this
setup.py
En las tests/__init__.py
, desea importar la prueba de unidad y la secuencia de prueba de su unidad test_module
y luego crear una función para ejecutar las pruebas. En tests/__init__.py
, escribe algo como esto:
import unittest
import test_module
def my_module_suite():
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(test_module)
return suite
La clase TestLoader
tiene otras funciones además de loadTestsFromModule
. Puede ejecutar dir(unittest.TestLoader)
para ver los otros, pero este es el más simple de usar.
Dado que la estructura de su directorio es tal, probablemente querrá que test_module
pueda importar su script de module
. Es posible que ya haya hecho esto, pero en caso de que no lo haya hecho, podría incluir la ruta primaria para que pueda importar el módulo del package
y el script del module
. En la parte superior de tu test_module.py
, escribe:
import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ''..'')))
import unittest
import package.module
...
Finalmente, en setup.py
, incluye el módulo de tests
y ejecuta el comando que creaste, my_module_suite
:
from setuptools import setup, find_packages
setup(
...
test_suite = ''tests.my_module_suite'',
...
)
Luego, solo ejecuta la python setup.py test
.
Aquí hay una sample alguien hizo como referencia.
Otra solución menos que ideal ligeramente inspirada por http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py
Agregue un módulo que devuelva TestSuite
de pruebas descubiertas. Luego configure la configuración para llamar a ese módulo.
project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
discover_tests.py
setup.py
Aquí está discover_tests.py
:
import os
import sys
import unittest
def additional_tests():
setup_file = sys.modules[''__main__''].__file__
setup_dir = os.path.abspath(os.path.dirname(setup_file))
return unittest.defaultTestLoader.discover(setup_dir)
Y aquí está setup.py
:
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
config = {
''name'': ''name'',
''version'': ''version'',
''url'': ''http://example.com'',
''test_suite'': ''discover_tests'',
}
setup(**config)
Si usa py27 + o py32 +, la solución es bastante simple:
test_suite="tests",
Una posible solución es simplemente extender el comando de test
para distutils
y setuptools
/ distribute
. Esto parece un kluge total y mucho más complicado de lo que yo preferiría, pero parece descubrir y ejecutar correctamente todas las pruebas en mi paquete al ejecutar la python setup.py test
. Me estoy retrasando al seleccionar esto como la respuesta a mi pregunta con la esperanza de que alguien proporcione una solución más elegante :)
(Inspirado por https://docs.pytest.org/en/latest/goodpractices.html#integrating-with-setuptools-python-setup-py-test-pytest-runner )
Ejemplo setup.py
:
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
def discover_and_run_tests():
import os
import sys
import unittest
# get setup.py directory
setup_file = sys.modules[''__main__''].__file__
setup_dir = os.path.abspath(os.path.dirname(setup_file))
# use the default shared TestLoader instance
test_loader = unittest.defaultTestLoader
# use the basic test runner that outputs to sys.stderr
test_runner = unittest.TextTestRunner()
# automatically discover all tests
# NOTE: only works for python 2.7 and later
test_suite = test_loader.discover(setup_dir)
# run the test suite
test_runner.run(test_suite)
try:
from setuptools.command.test import test
class DiscoverTest(test):
def finalize_options(self):
test.finalize_options(self)
self.test_args = []
self.test_suite = True
def run_tests(self):
discover_and_run_tests()
except ImportError:
from distutils.core import Command
class DiscoverTest(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
discover_and_run_tests()
config = {
''name'': ''name'',
''version'': ''version'',
''url'': ''http://example.com'',
''cmdclass'': {''test'': DiscoverTest},
}
setup(**config)