python setup.py test
を取得してpython -m unittest discover
に相当するものを実行する方法を見つけようとしています。 run_tests.pyスクリプトを使用したくないし、外部テストツール(nose
やpy.test
など)を使用したくない。ソリューションがpython 2.7でのみ動作する場合は問題ありません。
setup.py
で、configのtest_suite
および/またはtest_loader
フィールドに何かを追加する必要があると思いますが、正しく機能する組み合わせを見つけることができないようです:
config = {
'name': name,
'version': version,
'url': url,
'test_suite': '???',
'test_loader': '???',
}
これは、python 2.7?に組み込まれたunittest
のみを使用して可能ですか?
参考までに、私のプロジェクト構造は次のようになります。
project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
run_tests.py <- I want to delete this
setup.py
Update:これはunittest2
で可能ですが、unittest
のみを使用して同等のものを見つけたい
https://pypi.python.org/pypi/unittest2 から
unittest2には、非常に基本的なsetuptools互換のテストコレクターが含まれています。 setup.pyでtest_suite = 'unittest2.collector'を指定します。これにより、setup.pyを含むディレクトリからデフォルトパラメータを使用してテスト検出が開始されるため、おそらく例として最も有用です(unittest2/collector.pyを参照)。
今のところ、run_tests.py
と呼ばれるスクリプトを使用していますが、python setup.py test
のみを使用するソリューションに移行することでこれを解消できることを望んでいます。
削除したいrun_tests.py
は次のとおりです。
import unittest
if __== '__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 +を使用する場合、解決策は非常に簡単です。
test_suite="tests",
Setuptoolsを使用したパッケージのビルドおよび配布 (私の強調):
test_suite
Unittest.TestCaseサブクラス(または1つ以上のサブクラスを含むパッケージまたはモジュール、またはそのようなサブクラスのメソッド)を命名する文字列、または引数なしで呼び出すことができる関数の命名 unittest.TestSuiteを返します。
したがって、setup.py
TestSuiteを返す関数を追加します。
import unittest
def my_test_suite():
test_loader = unittest.TestLoader()
test_suite = test_loader.discover('tests', pattern='test_*.py')
return test_suite
次に、コマンドsetup
を次のように指定します。
setup(
...
test_suite='setup.my_test_suite',
...
)
これを機能させるために設定は必要ありません。基本的には、主に2つの方法があります。
簡単な方法
_test_module.py
_の名前を_module_test.py
_に変更し(基本的に__test
_をサフィックスとして特定のモジュールのテストに追加します)、pythonで自動的に検出されます。必ず_setup.py
_に追加してください:
_from setuptools import setup, find_packages
setup(
...
test_suite = 'tests',
...
)
_
長い道のり
現在のディレクトリ構造でそれを行う方法は次のとおりです。
_project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
run_tests.py <- I want to delete this
setup.py
_
_tests/__init__.py
_の下で、unittest
と単体テストスクリプト_test_module
_をインポートし、テストを実行する関数を作成します。 _tests/__init__.py
_に、次のように入力します。
_import unittest
import test_module
def my_module_suite():
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(test_module)
return suite
_
TestLoader
クラスには、loadTestsFromModule
以外の関数があります。 dir(unittest.TestLoader)
を実行して他のものを見ることができますが、これは最も簡単に使用できます。
ディレクトリ構造はそのようなものなので、おそらく_test_module
_がmodule
スクリプトをインポートできるようにする必要があります。すでにこれを行っているかもしれませんが、念のため、親パスを含めて、package
モジュールとmodule
スクリプトをインポートできます。 _test_module.py
_の上部で、次を入力します。
_import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import unittest
import package.module
...
_
最後に、_setup.py
_にtests
モジュールを含めて、作成したコマンド_my_module_suite
_を実行します。
_from setuptools import setup, find_packages
setup(
...
test_suite = 'tests.my_module_suite',
...
)
_
次に、_python setup.py test
_を実行します。
サンプル 参照として作成された誰かです。
可能な解決策の1つは、test
およびdistutils
/setuptools
のdistribute
コマンドを単純に拡張することです。これは私が好むよりも複雑で複雑なように思えますが、python setup.py test
。誰かがよりエレガントなソリューションを提供してくれることを期待して、私の質問への回答としてこれを選択することを保留しています:)
例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)
Pythonの標準ライブラリunittest
モジュールはディスカバリをサポートしています(Python 2.7以降、およびPython 3.2以降)。これらの最小値を想定できる場合バージョンの場合は、discover
コマンドライン引数をunittest
コマンドに追加するだけです。
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,
},
)
http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py に少し触発された別の理想的ではないソリューション
検出されたテストのTestSuite
を返すモジュールを追加します。次に、そのモジュールを呼び出すようにセットアップを構成します。
project/
package/
__init__.py
module.py
tests/
__init__.py
test_module.py
discover_tests.py
setup.py
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)
そして、ここに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)
これはrun_tests.pyを削除しませんが、setuptoolsで動作します。追加:
_class Loader(unittest.TestLoader):
def loadTestsFromNames(self, names, _=None):
return self.discover(names[0])
_
それからsetup.pyで:(setup(**config)
のようなことをしていると仮定します)
_config = {
...
'test_loader': 'run_tests:Loader',
'test_suite': '.', # your start_dir for discover()
}
_
唯一の欠点は、loadTestsFromNames
のセマンティクスを曲げていることですが、setuptoolsテストコマンドが唯一のコンシューマであり、 指定された方法 で呼び出します。