単純なPythonモジュールでも非常に一般的なディレクトリ構造は、単体テストを独自のtest
ディレクトリに分割することです。
new_project/
antigravity/
antigravity.py
test/
test_antigravity.py
setup.py
etc.
例えば、こちら のPythonプロジェクトの手引き をご覧ください。
私の質問は単純です実際にテストを実行する通常の方法は何ですか?これは私以外のすべての人にとって明らかなことですが、テストディレクトリからpython test_antigravity.py
を実行することはできません。モジュールがパス上にないため、import antigravity
は失敗します。
PYTHONPATHや他の検索パスに関連するトリックを変更することはできますが、それが最も簡単な方法であるとは思えません。開発者であれば問題ありません。通過。
もう1つの方法は、テストファイルを他のディレクトリにコピーすることですが、少し愚かに見え、最初は別のディレクトリに置くという点を見逃しています。
それで、あなたがちょうど私の新しいプロジェクトにソースをダウンロードしたならば、どのようにあなたは単体テストを実行するでしょうか?私は私のユーザーに私に言うことができる答えが欲しいです: "ユニットテストを実行するにはXをしてください。"
私の考えでは、最良の解決策は、ディレクトリをsys.path
に追加するunittest
コマンドラインインタフェース を使用することです。 TestLoader
クラス).
たとえば、次のようなディレクトリ構造の場合
new_project
├── antigravity.py
└── test_antigravity.py
あなただけ実行することができます:
$ cd new_project
$ python -m unittest test_antigravity
あなたのようなディレクトリ構造の場合:
new_project
├── antigravity
│ ├── __init__.py # make it a package
│ └── antigravity.py
└── test
├── __init__.py # also make test a package
└── test_antigravity.py
test
パッケージ内のテストモジュールでは、antigravity
パッケージとそのモジュールを通常どおりインポートできます。
# import the package
import antigravity
# import the antigravity module
from antigravity import antigravity
# or an object inside the antigravity module
from antigravity.antigravity import my_object
単一のテストモジュールを実行する:
単一のテストモジュールを実行するには、この場合test_antigravity.py
:
$ cd new_project
$ python -m unittest test.test_antigravity
テストモジュールをインポートするのと同じ方法で参照してください。
単一のテストケースまたはテストメソッドを実行する:
また、単一のTestCase
または単一のテストメソッドを実行することもできます。
$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method
すべてのテストを実行中:
また、 テストディスカバリー を使用して、すべてのテストを検出して実行することもできます。それらはtest*.py
という名前のモジュールまたはパッケージでなければなりません(-p, --pattern
で変更できます)フラグ):
$ cd new_project
$ python -m unittest discover
これはtest
パッケージ内のすべてのtest*.py
モジュールを実行します。
ユーザーにとって最も簡単な解決策は、必要に応じて一時的にsys.pathにルートプロジェクトディレクトリを追加するなど、必要なテスト環境をブートストラップする実行可能スクリプト(runtests.py
など)を提供することです。これはユーザーが環境変数を設定することを要求しません、ブートストラップスクリプトでこのようなものはうまく働きます:
import sys, os
sys.path.insert(0, os.path.dirname(__file__))
それからあなたのユーザへのあなたの指示は "python runtests.py"と同じくらい簡単になることができます。
もちろん、必要なパスがos.path.dirname(__file__)
であれば、それをsys.path
に追加する必要はまったくありません。 Pythonは常に現在実行中のスクリプトのディレクトリをsys.path
の先頭に置くので、ディレクトリ構造によっては、正しい場所にruntests.py
を配置するだけでよい場合があります。
また、Python 2.7の unittestモジュールには+ (Python 2.6以前では unittest2 としてバックポートされています)が になりました。 ]テストディスカバリ ビルトインなので、自動テストディスカバリをしたいのであれば、もはや鼻は必要ありません。ユーザの指示は "python -m unittest discover"と同じくらい簡単です。
私は通常、プロジェクトディレクトリ(ソースディレクトリとtest
の両方に共通のもの)に "テストの実行"スクリプトを作成して、 "すべてのテスト"スイートをロードします。これは通常定型コードなので、プロジェクトごとに再利用できます。
run_tests.py:
import unittest
import test.all_tests
testSuite = test.all_tests.create_test_suite()
text_runner = unittest.TextTestRunner().run(testSuite)
test/all_tests.py(from すべてのPythonユニットテストをディレクトリで実行するにはどうすればよいですか? )
import glob
import unittest
def create_test_suite():
test_file_strings = glob.glob('test/test_*.py')
module_strings = ['test.'+str[5:len(str)-3] for str in test_file_strings]
suites = [unittest.defaultTestLoader.loadTestsFromName(name) \
for name in module_strings]
testSuite = unittest.TestSuite(suites)
return testSuite
この設定では、テストモジュールの中で本当にinclude antigravity
だけできます。欠点は、特定のテストを実行するためのサポートコードがもっと必要になることです...私は毎回それらをすべて実行します。
あなたがリンクした記事から:
Test_modulename.pyファイルを作成し、そこにあなたのunittestテストを入れてください。テストモジュールはコードとは別のディレクトリにあるため、それらを実行するには、モジュールの親ディレクトリをPYTHONPATHに追加する必要があります。
$ cd /path/to/googlemaps $ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps $ python test/test_googlemaps.py
最後に、Python用のもう1つの一般的な単体テストフレームワークがあります(それはとても重要です)。 noseは、組み込みのunittestフレームワークを単純化し拡張するのに役立ちます(例えば、テストコードを自動的に見つけてPYTHONPATHを自動的に設定することができます)が、標準のPython配布には含まれていません。
おそらく、あなたは 鼻 を見てみるべきでしょうか?
"python setup.py Develop"を実行すると、パッケージはパスに入ります。しかし、あなたはあなたのシステムのpythonインストールに感染する可能性があるのでそれをしたくないかもしれません、それは virtualenv や buildout のようなツールが存在する理由です。
私は別のユニットテストフォルダで、同じ問題を抱えていました。前述の提案から、私は絶対ソースパスをsys.path
に追加します。
次の解決策の利点は、最初にtestディレクトリに変更することなくファイルtest/test_yourmodule.py
を実行できることです。
import sys, os
testdir = os.path.dirname(__file__)
srcdir = '../antigravity'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))
import antigravity
import unittest
VS Codeを使用していて、テストがプロジェクトと同じレベルにある場合は、コードの実行とデバッグはそのままでは機能しません。できることは、launch.jsonファイルを変更することです。
{
"version": "0.2.0",
"configurations": [
{
"name": "Python",
"type": "python",
"request": "launch",
"stopOnEntry": false,
"pythonPath": "${config:python.pythonPath}",
"program": "${file}",
"cwd": "${workspaceRoot}",
"env": {},
"envFile": "${workspaceRoot}/.env",
"debugOptions": [
"WaitOnAbnormalExit",
"WaitOnNormalExit",
"RedirectOutput"
]
}
]
}
ここでのキーラインはenvFileです。
"envFile": "${workspaceRoot}/.env",
プロジェクトのルートに.envファイルを追加します。
.envファイルの中に、プロジェクトのルートへのパスを追加します。これは一時的に追加されます
PYTHONPATH = C:\あなたの\ PYTHON\PROJECT\ROOT_DIRECTORY
プロジェクトへのパスを入力すると、VS Codeのデバッグ単体テストを使用できるようになります。
Python unittestモジュールのための解決策/例
以下のプロジェクト構造を考えます。
ProjectName
├── project_name
| ├── models
| | └── thing_1.py
| └── __main__.py
└── test
├── models
| └── test_thing_1.py
└── __main__.py
python project_name
を呼び出すProjectName/project_name/__main__.py
を使用して、ルートディレクトリからプロジェクトを実行できます。
python test
を使用してテストを実行し、効果的にProjectName/test/__main__.py
を実行するには、次の手順を実行する必要があります。
1)test/models
ファイルを追加して、__init__.py
ディレクトリをパッケージにします。これにより、サブディレクトリ内のテストケースは、親のtest
ディレクトリからアクセス可能になります。
# ProjectName/test/models/__init__.py
from .test_thing_1 import Thing1TestCase
2)test/__main__.py
内のシステムパスを、project_name
ディレクトリを含むように変更します。
# ProjectName/test/__main__.py
import sys
import unittest
sys.path.append('../project_name')
loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)
これで、テストでproject_name
から正常にインポートできました。
# ProjectName/test/models/test_thing_1.py
import unittest
from project_name.models import Thing1 # this doesn't work without 'sys.path.append' per step 2 above
class Thing1TestCase(unittest.TestCase):
def test_thing_1_init(self):
thing_id = 'ABC'
thing1 = Thing1(thing_id)
self.assertEqual(thing_id, thing.id)
作業ディレクトリをインストール済みのPython環境の一部にするためにsetup.py develop
を使用してから、テストを実行します。
選択したテストまたはすべてのテストを実行するラッパーを使用することができます。
例えば:
./run_tests antigravity/*.py
またはすべてのテストを再帰的に実行するには、 globbing (tests/**/*.py
)を使用します(shopt -s globstar
で有効にします)。
ラッパーは基本的にargparse
を使用して以下のように引数を解析できます。
parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*')
それからすべてのテストをロードします。
for filename in args.files:
exec(open(filename).read())
それからそれらをテストスイートに追加します(inspect
を使用)。
alltests = unittest.TestSuite()
for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj) and name.startswith("FooTest"):
alltests.addTest(unittest.makeSuite(obj))
そしてそれらを実行します。
result = unittest.TextTestRunner(verbosity=2).run(alltests)
詳細は this exampleを確認してください。
あなたの "src"ディレクトリからunittestのコマンドラインインターフェイスを実行すれば、インポートは変更なしで正しく動作することに気づきました。
python -m unittest discover -s ../test
プロジェクトディレクトリのバッチファイルに入れたい場合は、次のようにします。
setlocal & cd src & python -m unittest discover -s ../test
以下は私のプロジェクト構造です。
ProjectFolder:
- project:
- __init__.py
- item.py
- tests:
- test_item.py
SetUp()メソッドでインポートした方が良いことがわかりました。
import unittest
import sys
class ItemTest(unittest.TestCase):
def setUp(self):
sys.path.insert(0, "../project")
from project import item
# further setup using this import
def test_item_props(self):
# do my assertions
if __== "__main__":
unittest.main()
実際にテストを実行する通常の方法は何ですか
私はPython 3.6.2を使っています
cd new_project
pytest test/test_antigravity.py
pytestをインストールするには:Sudo pip install pytest
パス変数を設定しなかったので、インポートが同じ「テスト」プロジェクト構造で失敗することはありません。
私はこのことをコメントアウトしました:if __== '__main__'
はこのように:
test_antigravity.py
import antigravity
class TestAntigravity(unittest.TestCase):
def test_something(self):
# ... test stuff here
# if __== '__main__':
#
# if __package__ is None:
#
# import something
# sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
# from .. import antigravity
#
# else:
#
# from .. import antigravity
#
# unittest.main()
@Pierreに追加する
このようにunittest
ディレクトリ構造を使う:
new_project
├── antigravity
│ ├── __init__.py # make it a package
│ └── antigravity.py
└── test
├── __init__.py # also make test a package
└── test_antigravity.py
テストモジュールtest_antigravity.py
を実行するには
$ cd new_project
$ python -m unittest test.test_antigravity
あるいは単一のTestCase
$ python -m unittest test.test_antigravity.GravityTestCase
必須空でも__init__.py
を忘れないでください。
あなたは、なんらかのブードゥーがなければ、親ディレクトリからインポートすることはできません。これは少なくともPython 3.6で動作するもう一つの方法です。
まず、test/context.pyファイルに次の内容を入れます。
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
次に、test/test_antigravity.pyファイルに次のインポートを入れます。
import unittest
try:
import context
except ModuleNotFoundError:
import test.context
import antigravity
このtry-except節の理由は、
このトリックで、彼らは両方とも働きます。
これで、testディレクトリ内のテストファイルをすべてall実行することができます。
$ pwd
/projects/new_project
$ python -m unittest
または個別のテストファイルを次のように実行します。
$ cd test
$ python test_antigravity
わかりました、test_antigravity.pyの中にcontext.pyの内容を入れるよりもきれいではありませんが、少しだけかもしれません。提案は大歓迎です。
このBASHスクリプトはファイルシステムのどこからでもpythonのunittestテストディレクトリを実行します。どんな作業ディレクトリにいても関係ありません。
これは./src
または./example
作業ディレクトリにいるときに便利で、簡単な単体テストが必要です。
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"
python -m unittest discover -s "$readlink"/test -v
プロダクション中にあなたのパッケージ/メモリオーバーヘッドを負担するためにtest/__init__.py
ファイルを必要としません。
テストディレクトリに複数のディレクトリがある場合は、各ディレクトリに__init__.py
ファイルを追加する必要があります。
/home/johndoe/snakeoil
└── test
├── __init__.py
└── frontend
└── __init__.py
└── test_foo.py
└── backend
└── __init__.py
└── test_bar.py
それからすべてのテストを一度に実行するには、次のように実行します。
python -m unittest discover -s /home/johndoe/snakeoil/test -t /home/johndoe/snakeoil
ソース:python -m unittest -h
-s START, --start-directory START
Directory to start discovery ('.' default)
-t TOP, --top-level-directory TOP
Top level directory of project (defaults to start
directory)
この方法により、コマンドラインからシステム変数をいじることなく、どこからでもテストスクリプトを実行できます。
これにより、メインプロジェクトフォルダーがpythonパスに追加されます。その場所は、現在の作業ディレクトリではなく、スクリプト自体に関連して検出されます。
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
すべてのテストスクリプトの先頭に追加します。これにより、システムパスにメインプロジェクトフォルダーが追加されるため、そこから機能するモジュールインポートはすべて機能するようになります。そして、どこからテストを実行するかは問題ではありません。
明らかに、project_path_hackファイルを変更して、メインプロジェクトフォルダーの場所に一致させることができます。
あなたは本当にpipツールを使うべきです。
開発モードでパッケージをインストールするにはpip install -e .
を使用してください。これはpytestによって推奨される非常に良い習慣です(彼らが従うべき2つのプロジェクトレイアウトを見つけることができるそこで彼らの 良い習慣ドキュメンテーション を見てください)。
コマンドラインのみの解決策を探しているなら:
次のディレクトリ構造に基づいています(専用のソースディレクトリで一般化されています)。
new_project/
src/
antigravity.py
test/
test_antigravity.py
Windows:(new_project
内)
$ set PYTHONPATH=%PYTHONPATH%;%cd%\src
$ python -m unittest discover -s test
これをバッチforループで使用したい場合は、この質問を参照してください。
Linux:(new_project
内)
$ export PYTHONPATH=$PYTHONPATH:$(pwd)/src [I think - please edit this answer if you are a Linux user and you know this]
$ python -m unittest discover -s test
この方法では、必要に応じてPYTHONPATHにディレクトリを追加することもできます。