Python単体テストはどこに行くのですか?


490

ライブラリまたはアプリを作成している場合、単体テストファイルはどこに行きますか?

テストファイルをメインアプリのコードから分離するのは良いことですが、テストするモジュールをインポートするのが難しくなるため、アプリのルートディレクトリ内の「tests」サブディレクトリにそれらを配置するのは厄介です。

ここにベストプラクティスはありますか?


4
この質問には多くの受け入れられる回答があり、それはQ / Aサイトにとっては問題ではありません。人々は、役に立つ役立つ質問のすべてがSOで尋ねられるわけではないことを理解する必要があります。前者はそれを選択し、私たちは彼らのルールに従う必要があります。
Wouter J

121
また、SOページが最終的にGoogle検索のトップヒットになる場合は、SOの公式理念に固執するのではなく、フローに沿って進む方がよいことを人々は理解する必要もあります。
Christopher Barber

6
@ChristopherBarberの人々はまた、決定と積極的な閉鎖が、私が本当に本当により良い選択肢がない限り、質問をしないほうがいいサイトとして、ひどい評判を得ることになったことを理解する必要もあります。
Stefano Borini、

回答:


200

ファイルのmodule.py場合、ユニットテストは通常test_module.py、Pythonの命名規則に従って呼び出されます。

一般的に受け入れられている場所がいくつかありますtest_module.py

  1. と同じディレクトリmodule.py
  2. ../tests/test_module.py(コードディレクトリと同じレベル)。
  3. tests/test_module.py(コードディレクトリの下にあるレベル)。

テストを見つけてインポートするのが簡単なため、私は#1を好みます。どのビルドシステムを使用していても、で始まるファイルを実行するように簡単に構成できますtest_。実際、テスト検出に使用されるデフォルトのunittestパターンはtest*.pyです。


12
load_testsプロトコルデフォルトでテスト*の.pyという名前のファイルを検索します。また、この上位のGoogleの結果この単体テストのドキュメントはどちらもtest_module.py形式を使用しています。
dfarrell07 2013

6
'test_'で始まるファイルの束がないため、タブ補完を使用する場合、foo_test.pyを使用すると、キーストロークを1つまたは2つ節約できます。
ジュニパー

11
@juniper、あなたの考えに従って、あなたがコーディングしているときにmodule_testはオートコンプリートに現れます。これは混乱を招く、または煩わしい場合があります。
Medeiros 2013年

11
コードをデプロイするとき、テストを本番ロケーションにデプロイしたくありません。したがって、これらを1つのディレクトリ './tests/test_blah.py'に置くと、デプロイメントを行うときに簡単にヤンクできます。また、一部のテストはサンプルデータファイルを取得します。テストデータを展開するために、それらをテストディレクトリに配置することが重要です。
ケビンJ.ライス

1
@ KevinJ.Riceコードが本番環境で機能することをテストしてはいけませんか?
内部石2017年

67

1つのテストファイルのみ

テストファイルが1つしかない場合は、最上位ディレクトリに配置することをお勧めします。

module/
    lib/
        __init__.py
        module.py
    test.py

CLIでテストを実行する

python test.py

多くのテストファイル

多くのテストファイルがある場合は、それをtestsフォルダーに配置します。

module/
    lib/
        __init__.py
        module.py
    tests/
        test_module.py
        test_module_function.py
# test_module.py

import unittest
from lib import module

class TestModule(unittest.TestCase):
    def test_module(self):
        pass

if __name__ == '__main__':
    unittest.main()

CLIでテストを実行する

# In top-level /module/ folder
python -m tests.test_module
python -m tests.test_module_function

使用する unittest discovery

unittest discovery すべてのテストはパッケージフォルダーにあります。

作成__init__.pytests/フォルダ

module/
    lib/
        __init__.py
        module.py
    tests/
        __init__.py
        test_module.py
        test_module_function.py

CLIでテストを実行する

# In top-level /module/ folder

# -s, --start-directory (default current directory)
# -p, --pattern (default test*.py)

python -m unittest discover

参照

単体テストフレームワーク


51

一般的な方法は、testsディレクトリをモジュール/パッケージと同じ親ディレクトリに置くことです。したがって、モジュールがfoo.pyと呼ばれた場合、ディレクトリレイアウトは次のようになります。

parent_dir/
  foo.py
  tests/

もちろん、それを行う方法は1つではありません。また、testsサブディレクトリを作成し、絶対インポートを使用してモジュールをインポートすることもできます。

テストをどこに置いても、を使って実行することをお勧めします。Noseはディレクトリをテストして検索します。このようにして、組織的に最も意味のある場所にテストを配置できます。


16
これを実行したいのですが、機能させることができません。テストを実行するには、parent_dirに移動して、「python tests \ foo_test.py」と入力し、foo_test.py:「from ..foo import this、that、theother」と入力します。「ValueError:Attempted非パッケージでの相対インポート」parent_dirとテストの両方にinit .pyが含まれているため、パッケージでない理由がわかりません。init .pyのあるdirにある場合でも、コマンドラインから実行する最上位のスクリプトをパッケージ(の一部)と見なすことができないためと考えられます。では、テストを実行するにはどうすればよいですか?今日はWindowsに取り組んでいます。綿の靴下を祝福してください。
ジョナサンハートレイ

4
単体テストを実行する最良の方法-私が見つけた-は、ライブラリ/プログラムをインストールしてから、鼻で単体テストを実行することです。これをはるかに簡単にするために、virtualenvおよびvirtualenvwrapperをお勧めします。
クリスティアン

@Tartley- absolutionインポートを機能させるには、 'tests'ディレクトリにinit .pyファイルが必要です。私はこの方法を鼻で使用しているので、なぜあなたが問題を抱えているのかわかりません。
cmcginty 2009年

4
ありがとうケーシー-しかし、私はすべての関連ディレクトリにinit .pyファイルを持っています。私は何が悪いのかわかりませんが、すべてのPythonプロジェクトでこの問題が発生し、他の人が何をしないのか理解できません。ああ、まあ。
ジョナサンハートレイ

8
私の問題の1つの解決策は、Python2.6以降で、次のコマンドを使用してプロジェクトのルートからテストを実行することです。 。これにより、テストモジュールのディレクトリがパスに配置されるため、テストは親ディレクトリへの相対インポートを実行して、テスト対象のモジュールを取得できます。
ジョナサンハートレイ

32

Pythonプログラムの単体テストを生成するPythoscope(https://pypi.org/project/pythoscope/)を作成するときにも、同じ質問がありました。ディレクトリを選択する前に、Pythonリストのテストで人々に投票したところ、さまざまな意見がありました。最後に、「tests」ディレクトリをソースコードと同じディレクトリに配置することを選択しました。そのディレクトリで、親ディレクトリ内の各モジュールのテストファイルを生成します。


2
驚くばかり!いくつかのレガシーコードでPythoscope(素晴らしいロゴ)を実行しただけで、それは素晴らしいものでした。すぐにベストプラクティスが得られ、他の開発者に、現在失敗しているテストスタブに記入してもらうことができます。それを竹につなぎますか?:)
ウィル

27

上記のJeremy Cantrellが注記しているように、単体テストもファイルに入れる傾向がありますが、本体にテスト関数を入れるのではなく、すべてを

if __name__ == '__main__':
   do tests...

ブロック。これは、テストしているpythonファイルの使用方法の「サンプルコード」としてドキュメントにファイルを追加することになります。

追加すべきですが、非常にタイトなモジュール/クラスを書く傾向があります。モジュールに非常に多数のテストが必要な場合は、別のテストに配置できますが、それでも、次のように追加します。

if __name__ == '__main__':
   import tests.thisModule
   tests.thisModule.runtests

これにより、ソースコードを読んでいる誰もがテストコードを探す場所を知ることができます。


「メモの上のジェレミー・カントレルとして」どこに?
内部石2014

私はこの働き方が好きです。最も単純なエディターは、ホットキーでファイルを実行するように構成できるため、コードを表示しているときに、テストを瞬時に実行できます。残念ながら、Python以外の言語ではこれは恐ろしく見える可能性があるため、C ++やJavaのショップを利用している場合、同僚はこれを嫌うかもしれません。また、コードカバレッジツールではうまく機能しません。
Keeely

19

時々、私はテストの配置のトピックをチェックしていることに気付き、大多数がライブラリコードの横にある別のフォルダー構造を推奨するたびに、引数が同じであり、説得力があるとは限りません。結局、テストモジュールをコアモジュールの横に置きます。

これを行う主な理由は、リファクタリングです。

物事を移動するときは、テストモジュールをコードと一緒に移動する必要があります。テストが別のツリーにある場合、テストを失うのは簡単です。正直に言うと、遅かれ早かれ、djangoフラスコなど、まったく異なるフォルダー構造になってしまいます。あなたが気にしないならそれは問題ありません。

あなたが自問すべき主な質問はこれです:

私は書いていますか:

  • a)再利用可能なライブラリまたは
  • b)いくつかの半分離モジュールを一緒にバンドルするよりもプロジェクトを構築しますか?

もし:

別のフォルダーとその構造を維持するための余分な労力が適している場合があります。テストが本番環境にデプロイされることに不満を言う人はいません。

しかし、コアフォルダーと混在しているテストを配布から除外するのも同じくらい簡単です。これをsetup.pyに入れます

find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"]) 

bの場合:

私たちの誰もがそうであるように、再利用可能なライブラリを作成することを望むかもしれませんが、ほとんどの場合、それらのライフはプロジェクトのライフに結びついています。プロジェクトを簡単に維持できることが優先事項です。

次に、適切な作業を行い、モジュールが別のプロジェクトに適している場合は、おそらく、フォークされたり別のライブラリに作成されたりせずに、この新しいプロジェクトにコピーされ、同じフォルダー構造内の横にあるテストが移動します。別のテストフォルダーになった混乱でテストを釣り上げることに比べて簡単です。(そもそもごちゃごちゃにすべきではないと主張するかもしれませんが、ここでは現実的にしましょう)。

ですから、選択はあなた次第ですが、混合テストを使用すると、別のフォルダーを使用する場合とすべて同じことを達成できますが、整頓するための労力は少なくなります。


1
実際にテストをデプロイする際の問題は何ですか?私の経験では、それは非常に便利です:ユーザーが実際に環境でテストを実行できるようにします...バグレポートを受け取ったら、テストスイートを実行してすべてが問題ないことを確認し、テストのホットパッチを送信するようにユーザーに要求できます。スイート直接...ほかに、それはあなたがそれをすることをmodule.testsでテストを入れているためではないだろう ...あなたはあなたのセットアップファイルで何かを間違っていた場合を除き、生産に終わる
anarcat

2
私が私の回答に書いたように、私は通常テストを分離しません。だが。テストを配布パッケージに入れると、通常はプロダクション環境で不要なもの(モジュールレベルのコードなど)が実行される可能性があります。もちろん、テストの記述方法によって異なりますが、安全のため、テストをオフにしておくと、誰かが誤って何かを実行することはありません。ディストリビューションにテストを含めることに反対しているわけではありませんが、経験則としては安全であると理解しています。そして、それらを別のフォルダに置くと、distに含めるのが非常に簡単になります。
Janusz Skonieczny 2017年

15

tests/ディレクトリを使用し、相対インポートを使用してメインアプリケーションモジュールをインポートします。したがって、MyApp / tests / foo.pyには、次のようになります。

from .. import foo

MyApp.fooモジュールをインポートします。


5
「ValueError:非パッケージでの相対インポートの試み」
cprn

12

確立された「ベストプラクティス」があるとは思いません。

テストはアプリコードの外の別のディレクトリに配置しました。次に、すべてのテストを実行する前に、メインアプリディレクトリをsys.pathに追加します(どこからでもモジュールをインポートできるようにします)。これにより、リリース時にメインディレクトリからテストディレクトリを削除する必要がなくなり、時間と労力を節約できます。


3
次に、メインアプリディレクトリをsys.pathに追加します。問題は、テストにいくつかのヘルパーモジュール(テストWebサーバーなど)が含まれていて、適切なテスト内からそのようなヘルパーモジュールをインポートする必要がある場合です。
Piotr Dobrogost

これは私のためにどのように見えるかです:os.sys.path.append(os.dirname('..'))
マット・M.

11

Pythonでのテストフレームワークの開発における私の経験から、Python単体テストを別のディレクトリに置くことをお勧めします。対称的なディレクトリ構造を維持します。これは、単体テストをパッケージ化するのではなく、コアライブラリのみをパッケージ化するのに役立ちます。以下は、概略図で実装されています。

                              <Main Package>
                               /          \
                              /            \
                            lib           tests
                            /                \
             [module1.py, module2.py,  [ut_module1.py, ut_module2.py,
              module3.py  module4.py,   ut_module3.py, ut_module.py]
              __init__.py]

このようにして、rpmを使用してこれらのライブラリをパッケージ化すると、メインライブラリモジュール(のみ)をパッケージ化できます。これにより、特にアジャイル環境での保守性が向上します。


1
このアプローチの潜在的な利点の1つは、テストを独自の独立したアプリケーションとして開発できる(そしてバージョン管理さえできる)ことです。もちろん、あらゆる利点には欠点があります。対称性を維持することは、基本的に「複式簿記」を行うことであり、リファクタリングを面倒なものにします。
Jasha

ソフトなフォローアップの質問:なぜアジャイル環境は特にこのアプローチに特に適しているのですか?(つまり、アジャイルワークフローは対称ディレクトリ構造を非常に有益にしますか?)
Jasha

11

GitHubでいくつかの主要なPythonプロジェクトをチェックして、いくつかのアイデアを得ることをお勧めします。

コードが大きくなり、ライブラリを追加する場合は、setup.pyと同じディレクトリにテストフォルダーを作成し、各テストタイプ(unittest、integrationなど)のプロジェクトディレクトリ構造をミラー化することをお勧めします。

たとえば、次のようなディレクトリ構造があるとします。

myPackage/
    myapp/
       moduleA/
          __init__.py
          module_A.py
       moduleB/
          __init__.py
          module_B.py
setup.py

テストフォルダを追加すると、次のようなディレクトリ構造になります。

myPackage/
    myapp/
       moduleA/
          __init__.py
          module_A.py
       moduleB/
          __init__.py
          module_B.py
test/
   unit/
      myapp/
         moduleA/
            module_A_test.py
         moduleB/
            module_B_test.py
   integration/
          myapp/
             moduleA/
                module_A_test.py
             moduleB/
                module_B_test.py
setup.py

適切に記述されたPythonパッケージの多くは、同じ構造を使用しています。非常に良い例は、Botoパッケージです。https://github.com/boto/botoを確認してください


1
「test」はモジュール内のPythonビルドであるため、「test」の代わりに「tests」を使用することをお勧めします。docs.python.org/2/library/test.html
brodul 2017

常にではない..例えばmatplotlib下でそれを持っているmatplotlib/lib/matplotlib/testsgithub.com/matplotlib/matplotlib/tree/...)、sklearn下でそれを持っているscikitelearn/sklearn/testsgithub.com/scikit-learn/scikit-learn/tree/master/sklearn/tests
alpha_989

7

どうやって...

フォルダー構造:

project/
    src/
        code.py
    tests/
    setup.py

Setup.pyは、プロジェクトモジュールを含む場所としてsrc /を指し、次に実行します。

setup.py develop

これにより、プロジェクトがサイトパッケージに追加され、作業コピーが示されます。テストを実行するには、次を使用します。

setup.py tests

設定したテストランナーを使用します。


「モジュール」という用語を上書きしたようです。ほとんどのPythonプログラマーはおそらく、モジュールはあなたが呼び出したファイルだと思っているでしょうcode.py。トップレベルのディレクトリを「プロジェクト」と呼ぶ方が理にかなっています。
blokeley

4

私はトップレベルのテストディレクトリを好みます。これは、インポートがもう少し難しくなることを意味します。そのために私は2つの解決策を持っています:

  1. setuptoolsを使用します。次に、にパスtest_suite='tests.runalltests.suite'してsetup()、テストを簡単に実行できます。python setup.py test
  2. テストの実行時にPYTHONPATHを設定します。 PYTHONPATH=. python tests/runalltests.py

以下は、M2Cryptoのコードでそのようなものがサポートされる方法です。

nosetestsを使用してテストを実行したい場合は、少し異なる何かを行う必要があるかもしれません。


3

を使用しております

app/src/code.py
app/testing/code_test.py 
app/docs/..

各テストファイルにを挿入../src/sys.pathます。それは最も良い解決策ではありませんが、機能します。誰かがJavaのmavenのようなものを思いついたら、どんなプロジェクトに取り組んでいても、正常に機能する標準的な規則を提供できたら素晴らしいと思います。


1

テストが単純な場合は、単にそれらをdocstringに入れます-Pythonのほとんどのテストフレームワークはそれを使用できます。

>>> import module
>>> module.method('test')
'testresult'

他のより複雑なテストでは、私はどちらかに入れたい../tests/test_module.pyかでtests/test_module.py


1

C#では、通常、テストを個別のアセンブリに分離しました。

Pythonでは、これまでのところ、テストが関数のdocstringにあるdoctestを作成するかif __name__ == "__main__"、モジュールの下部のブロックに配置する傾向がありました。


0

「foo」というパッケージを作成するとき、単体テストを別のパッケージ「foo_test」に入れます。モジュールとサブパッケージは、SUTパッケージモジュールと同じ名前になります。たとえば、モジュールfoo.xyのテストはfoo_test.xyにあります。各テストパッケージの__init__.pyファイルには、パッケージのすべてのテストスイートを含むAllTestsスイートが含まれています。setuptoolsは、メインのテストパッケージを指定する便利な方法を提供します。これにより、「python setup.pydevelop」の後に「python setup.py test」または「python setup.py test -s foo_test.x.SomeTestSuite」を使用して、特定のスイートのみ。


0

テストをテスト対象コード(CUT)と同じディレクトリに配置しました。以下のためfoo.pyのテストになりますfoo_ut.pyまたは類似。(私はこれらを見つけるためにテスト発見プロセスを微調整します。)

これにより、テストがディレクトリリストのコードのすぐ横に配置され、テストがそこにあることが明らかになり、別のファイルにある場合と同じくらい簡単にテストを開くことができます。(コマンドラインエディターの場合、vim foo*およびグラフィカルファイルシステムブラウザーを使用する場合は、CUTファイルをクリックしてから、すぐ隣のテストファイルをクリックします。)

他の人が指摘している、これはまた、それが簡単にリファクタリングするとの使用のためのコードを抽出する他の場所でそれが今まで必要である必要があります。

まったく別のディレクトリツリーにテストを置くという考えは本当に嫌いです。開発者がCUTでファイルを開いているときにテストを開くことが必要以上に難しくなるのはなぜですか?大多数の開発者がテストの作成や微調整に熱心で、バリアを言い訳として使用する代わりに、バリアを無視するわけではありません。(私の経験では、まったく逆です。あなたができる限り簡単にしても、テストを書くことに煩わされない多くの開発者を知っています。)


-2

私は最近Pythonでプログラミングを始めたので、まだベストプラクティスを見つける機会はまだありませんでした。しかし、私は行ってすべてのテストを見つけて実行するモジュールを書きました。

ので、私は持っています:

app /
 appfile.py
テスト/
 appfileTest.py

大規模なプロジェクトに進むにつれ、どうなるかを確認する必要があります。


4
こんにちは、キャメルケースはPythonの世界では少し変です。
Stuart Axon、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.