86 votes

Comment exécuter unittest discover à partir de "python setup.py test" ?

J'essaie de comprendre comment obtenir python setup.py test pour exécuter l'équivalent de python -m unittest discover . Je ne veux pas utiliser un script run_tests.py script et je ne veux pas utiliser d'outils de test externes (comme nose o py.test ). Il n'y a pas de problème si la solution ne fonctionne que sur python 2.7.

En setup.py Je pense que je dois ajouter quelque chose à la rubrique test_suite et/ou test_loader dans la configuration, mais je n'arrive pas à trouver une combinaison qui fonctionne correctement :

config = {
    'name': name,
    'version': version,
    'url': url,
    'test_suite': '???',
    'test_loader': '???',
}

Est-ce possible en utilisant uniquement unittest intégré dans Python 2.7 ?

Pour information, la structure de mon projet est la suivante :

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  run_tests.py <- I want to delete this
  setup.py

Mise à jour : C'est possible avec unittest2 mais je veux trouver quelque chose d'équivalent en utilisant seulement unittest

De https://pypi.python.org/pypi/unittest2

unittest2 inclut un collecteur de tests très basique compatible avec setuptools. Spécifiez test_suite = 'unittest2.collector' dans votre setup.py. Ceci démarre la découverte des tests avec les paramètres par défaut du répertoire contenant setup.py, et est donc plus utile en tant qu'exemple (voir unittest2/collector.py).

Pour l'instant, j'utilise simplement un script appelé run_tests.py mais j'espère pouvoir m'en débarrasser en passant à une solution qui n'utilise que des python setup.py test .

Voici le run_tests.py J'espère pouvoir le retirer :

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)

47voto

saschpe Points 651

Si vous utilisez py27+ ou py32+, la solution est assez simple :

test_suite="tests",

41voto

De Construire et distribuer des paquets avec Setuptools (souligné par moi) :

suite_de_test

Une chaîne nommant une sous-classe de unittest.TestCase (ou un paquetage ou module contenant une ou plusieurs d'entre elles, ou une méthode d'une telle sous-classe une fonction qui peut être appelée sans arguments et qui renvoie une suite de tests unittest.TestSuite .

Ainsi, en setup.py vous devez ajouter une fonction qui renvoie une suite de tests :

import unittest
def my_test_suite():
    test_loader = unittest.TestLoader()
    test_suite = test_loader.discover('tests', pattern='test_*.py')
    return test_suite

Ensuite, vous devez spécifier la commande setup comme suit :

setup(
    ...
    test_suite='setup.my_test_suite',
    ...
)

20voto

gyeh Points 432

Vous n'avez pas besoin de configuration pour que cela fonctionne. Il y a deux façons principales de le faire :

La méthode rapide

Renommez votre test_module.py a module_test.py (en principe, ajouter _test comme suffixe aux tests pour un module particulier), et python le trouvera automatiquement. Assurez-vous simplement d'ajouter ceci à setup.py :

from setuptools import setup, find_packages

setup(
    ...
    test_suite = 'tests',
    ...
)

Le long chemin

Voici comment procéder avec votre structure de répertoire actuelle :

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  run_tests.py <- I want to delete this
  setup.py

En tests/__init__.py vous souhaitez importer le unittest et votre test unitaire script. test_module et créer une fonction pour exécuter les tests. En tests/__init__.py tapez quelque chose comme ceci :

import unittest
import test_module

def my_module_suite():
    loader = unittest.TestLoader()
    suite = loader.loadTestsFromModule(test_module)
    return suite

En TestLoader La classe a d'autres fonctions que loadTestsFromModule . Vous pouvez exécuter dir(unittest.TestLoader) pour voir les autres, mais celui-ci est le plus simple à utiliser.

Étant donné que votre structure de répertoire est telle, vous voudrez probablement que l'option test_module pour pouvoir importer votre module script. Vous l'avez peut-être déjà fait, mais au cas où vous ne l'auriez pas fait, vous pouvez inclure le chemin parent afin d'importer le fichier package et le module module script. Au début de votre test_module.py , type :

import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import unittest
import package.module
...

Enfin, en setup.py Les données de l'enquête sur l'état de santé de l'enfant comprennent les éléments suivants tests et exécutez la commande que vous avez créée, my_module_suite :

from setuptools import setup, find_packages

setup(
    ...
    test_suite = 'tests.my_module_suite',
    ...
)

Il suffit ensuite d'exécuter python setup.py test .

Voici un échantillon quelqu'un l'a fait comme référence.

6voto

cdwilson Points 632

Une solution possible est d'étendre simplement le test pour les distutils y setuptools / distribute . Cela semble être un kluge total et bien plus compliqué que ce que je préférerais, mais cela semble découvrir et exécuter correctement tous les tests dans mon paquetage en lançant python setup.py test . Je m'abstiens de choisir cette réponse à ma question dans l'espoir que quelqu'un fournisse une solution plus élégante :)

(Inspiré par https://docs.pytest.org/en/latest/goodpractices.html#integrating-with-setuptools-python-setup-py-test-pytest-runner )

Exemple 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)

3voto

cdwilson Points 632

Une autre solution moins qu'idéale, légèrement inspirée par http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py

Ajouter un module qui renvoie un TestSuite des tests découverts. Configurez ensuite l'installation pour qu'elle appelle ce module.

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  discover_tests.py
  setup.py

Voici 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)

Et voici 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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X