How to run unittest discover from “python setup.py test”?
我想知道如何让
在
1 2 3 4 5 6 7 | config = { 'name': name, 'version': version, 'url': url, 'test_suite': '???', 'test_loader': '???', } |
是否可以只使用内置在python 2.7中的
仅供参考,我的项目结构如下:
1 2 3 4 5 6 7 8 9 | project/ package/ __init__.py module.py tests/ __init__.py test_module.py run_tests.py <- I want to delete this setup.py |
更新:这在
来自https://pypi.python.org/pypi/unittest2
unittest2 includes a very basic setuptools compatible test collector. Specify test_suite = 'unittest2.collector' in your setup.py. This starts test discovery with the default parameters from the directory containing setup.py, so it is perhaps most useful as an example (see unittest2/collector.py).
目前,我只是在使用一个名为
这是我希望删除的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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) |
如果使用PY27+或PY32+,解决方案非常简单:
1 | test_suite="tests", |
从使用设置工具构建和分发包(重点是挖掘):
test_suite
A string naming a unittest.TestCase subclass (or a package or module
containing one or more of them, or a method of such a subclass), or naming
a function that can be called with no arguments and returns a unittest.TestSuite.
因此,在
1 2 3 4 5 | import unittest def my_test_suite(): test_loader = unittest.TestLoader() test_suite = test_loader.discover('tests', pattern='test_*.py') return test_suite |
然后,您将指定命令
1 2 3 4 5 | setup( ... test_suite='setup.my_test_suite', ... ) |
你不需要配置就能让它正常工作。主要有两种方法:
捷径
将您的
1 2 3 4 5 6 7 | from setuptools import setup, find_packages setup( ... test_suite = 'tests', ... ) |
漫长的道路
下面介绍如何使用当前目录结构:
1 2 3 4 5 6 7 8 9 | project/ package/ __init__.py module.py tests/ __init__.py test_module.py run_tests.py <- I want to delete this setup.py |
在
1 2 3 4 5 6 7 | import unittest import test_module def my_module_suite(): loader = unittest.TestLoader() suite = loader.loadTestsFromModule(test_module) return suite |
由于您的目录结构是这样的,您可能希望
1 2 3 4 5 6 | import os, sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) import unittest import package.module ... |
最后,在
1 2 3 4 5 6 7 | from setuptools import setup, find_packages setup( ... test_suite = 'tests.my_module_suite', ... ) |
然后你就运行
这是一个作为参考的样品。
一种可能的解决方案是简单地对
(灵感来源于https://docs.py test.org/en/latest/goodpractices.html与安装工具python安装py test pytest runner集成)
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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) |
python的标准库
对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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, }, ) |
另一个不太理想的解决方案受到了http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py的启发。
添加一个返回已发现测试的
1 2 3 4 5 6 7 8 9 | project/ package/ __init__.py module.py tests/ __init__.py test_module.py discover_tests.py setup.py |
这是
1 2 3 4 5 6 7 8 | 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) |
这是
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |
这不会删除run_tests.py,但会使它与安装工具一起工作。添加:
1 2 3 | class Loader(unittest.TestLoader): def loadTestsFromNames(self, names, _=None): return self.discover(names[0]) |
然后在setup.py中:(我假设你在做类似于
1 2 3 4 5 | config = { ... 'test_loader': 'run_tests:Loader', 'test_suite': '.', # your start_dir for discover() } |
我看到的唯一缺点是它扭曲了