私はpytestをPython 2.6。私のプログラムと同じ方法です。
私のディレクトリ構造は次のとおりです。
src/
main.py
util.py
test/
test_util.py
geom/
vector.py
region.py
test/
test_vector.py
test_region.py
実行するには、src /からpython main.py
を呼び出します。
Main.pyで、ベクターとリージョンの両方をインポートします
from geom.region import Region
from geom.vector import Vector
Vector.pyで、リージョンをインポートします
from geom.region import Region
標準実行でコードを実行すると、これらはすべて正常に機能します。ただし、src /から「py.test」を呼び出すと、インポートエラーで常に終了します。
私の最初の問題は、「test/test_foo.py」を実行するときに、py.testが「foo.pyを直接インポートできない」ということでした。 「imp」ツールを使用してこれを解決しました。 「test_util.py」内:
import imp
util = imp.load_source("util", "util.py")
これは多くのファイルに最適です。また、pytestが「path/foo/py」をテストするために「path/test/test_foo.py」を実行している場合、それはディレクトリ「path」に基づいていることを暗示しているようです。
ただし、「test_vector.py」ではこれは失敗します。 Pytestはvector
モジュールを見つけてインポートできますが、cannotvector
のインポートのいずれかを見つけます。 pytestを使用すると、( "vector.py"からの)次のインポートは両方とも失敗します。
from geom.region import *
from region import *
これらは両方ともフォームのエラーを与えます
ImportError: No module named [geom.region / region]
この問題を解決するために次に何をすべきかわかりません。 Pythonでのインポートの私の理解は限られています。
pytestを使用するときにインポートを処理する適切な方法は何ですか?
vector.py
で、インポートステートメントを
from geom.region import Region
単純に
from region import Region
これにより、インポートは「vector.py」のディレクトリに対して相対的になります。
次に、「test/test_vector.py」で、「vector.py」のディレクトリを次のようにパスに追加します。
import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))
これにより、Python= "geom/test/test_vector.py"から "../region.py"を見つけることができます。
これは機能しますが、大量の新しいディレクトリをパスに追加しているため、非常に問題が多いようです。私が探しているのは
1)pytestと互換性のあるインポート戦略、または
2)インポート戦略と互換性のあるpytestのオプション
ですから、私はこの種の答えのためにこの質問を開いたままにします。
importは、次のディレクトリを検索してモジュールを見つけます。
sys.pathは、home directory、[〜 #〜] pythonpath [〜#〜]および標準ライブラリディレクトリ。あなたがしていることは、sys.pathの修正が正しいことです。それは私が定期的に行うことです。 [=#〜] pythonpath [〜#〜]を使用してみてくださいsys.path
ここでの問題は、Pytestがファイルシステムを調べてテストを含むファイルを検出するが、import
がそのファイルをロードするようにするモジュール名を生成する必要があることです。 (覚えておいてください ファイルはモジュールではありません 。)
Pytestは、これを思い付きます テストパッケージ名__init__.py
ファイルを含まないファイルレベル以上の最初のディレクトリを見つけ、生成されたモジュールを含むモジュールツリーの「basedir」を宣言することによりこのファイルから。その後、basedirをsys.path
に追加し、basedirに関連するそのファイルを見つけるモジュール名を使用してインポートします。
これにはいくつか注意すべき点があります。
ベースパスが意図したベースパスと一致しない場合があります。その場合、モジュールの名前は通常使用するものと一致しません。たとえば、geom.test.test_vector
にtest_vector
が見つからず、そのディレクトリを__init__.py
に追加したため、Pytestの実行中にsrc/geom/test/
と考える名前は実際には単にsys.path
という名前になります。
異なるディレクトリにある2つのファイルの名前が同じ場合、モジュールの名前の衝突が発生する可能性があります。たとえば、__init__.py
ファイルがどこにもない場合、geom/test/test_util.py
を追加すると、test/test_util.py
と競合します。両方ともimport test_util.py
としてロードされ、パスにtest/
とgeom/test/
の両方が含まれます。
ここで使用しているシステムは、明示的な__init__.py
モジュールなしで、ディレクトリに対してPython create implicit namespace packages を持っています。パッケージはサブモジュールを持つモジュールです。)理想的には、Pytestでこれを生成するパスを設定するのが理想的ですが、その方法はわからないようです。
ここで最も簡単な解決策は、空の__init__.py
ファイルをsrc/
の下のすべてのサブディレクトリに追加することです。これにより、Pytestはsrc/
の下のディレクトリ名で始まるパッケージ/モジュール名を使用してすべてをインポートします。
質問 PEP 420名前空間パッケージを使用してプロジェクトをPytestする方法 では、これに対する他のソリューションについて説明しています。
私もこの問題について何をすべきか疑問に思っていました。この投稿を読んで、少し遊んだ後、私はエレガントな解決策を見つけました。 「test_setup.py」というファイルを作成し、次のコードをその中に配置しました。
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
このファイルを最上位ディレクトリ(srcなど)に配置します。 pytest
を最上位ディレクトリから実行すると、ファイルの先頭に「test」が付いているため、これを含むすべてのテストファイルが実行されます。ファイルにはテストはありませんが、「test」で始まるため、実行されたままです。
コードは、test_setup.pyファイルの現在のディレクトリ名をテスト環境内のシステムパスに追加します。これは一度だけ行われるため、パスに追加されるものはありません。
次に、任意のテスト関数内から、その最上位フォルダーに関連するモジュールをインポートできます(import geom.region
)そして、srcディレクトリがパスに追加されたので、それがどこにあるかを知っています。
すべてのファイルではなく、単一のテストファイル(test_util.pyなど)を実行する場合は、次を使用します。
pytest test_setup.py test\test_util.py
これにより、test_setupとtest_utilの両方のコードが実行されるため、test_setupコードを引き続き使用できます。