まずはプロジェクト初期化
$ poetry init
質問に回答しつつ、プロジェクトを初期化する。
ディレクトリ構成
以下のようなディレクトリ構成で進める。
src
にプロダクトコードが入っていて、tests
にテストコードが入っている状態を目指す。
$ tree .
.
├── poetry.lock
├── pyproject.toml
├── src
│ ├── hoge
│ │ ├── __init__.py
│ │ └── hoge.py
│ └── main.py
└── tests
└── test_main.py
プロダクトコード記述
src/main.py
は以下のような実装を書く。
from hoge.hoge import greet
# 動作確認用のmain関数
def main():
greet()
print('hello, world.')
# テストしたい関数
def add_one(number: int) -> int:
return number + 1
if __name__ == "__main__":
main()
src/hoge/hoge.py
にも適当な関数を記載しておく。
def greet():
print('こんにちは')
テストコード記述
tests/test_main.py
には、以下のように記述する。
main.py
に記載してあるadd_one
関数をテストするためのコード。
import src.main as main
def test_add_one():
assert main.add_one(1) == 2
pytestインストール
poetry経由でpytestをインストールする。
$ poetry add pytest
Using version ^8.3.3 for pytest
Updating dependencies
Resolving dependencies... (0.2s)
Package operations: 4 installs, 0 updates, 0 removals
- Installing iniconfig (2.0.0)
- Installing packaging (24.1)
- Installing pluggy (1.5.0)
- Installing pytest (8.3.3)
Writing lock file
これで始めてテストが実行できると思いきや、怒られる。
poetry run pytest
============================================================================= test session starts ==============================================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
rootdir: /Users/username/sample
configfile: pyproject.toml
collected 0 items / 1 error
==================================================================================== ERRORS ====================================================================================
_____________________________________________________________________ ERROR collecting tests/test_main.py ______________________________________________________________________
ImportError while importing test module '/Users/username/sample/tests/test_main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/local/Cellar/python@3.12/3.12.6/Frameworks/Python.framework/Versions/3.12/lib/python3.12/importlib/__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_main.py:1: in <module>
import src.main as main
E ModuleNotFoundError: No module named 'src'
=========================================================================== short test summary info ============================================================================
ERROR tests/test_main.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=============================================================================== 1 error in 0.07s ===============================================================================
ModuleNotFoundErrorの解消
これを解決するためのポイントは2つ。
①testsディレクトリに__init__.pyを配置する
初期のディレクトリ構成では配置を忘れているため、配置する。
②【重要】pyproject.tomlにpythonpathを明記する
モジュールの探索パスを指定するためpythonpath = "src"
というようにsrc
ディレクトリの指定を行う。
[tool.poetry]
name = "sample"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
pytest = "^8.3.3"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
pythonpath = "src"
詳しくは公式ドキュメントに記載してある。
Good Integration Practices - pytest documentation
pytest実行
テストが成功していることが確認できる。
$ poetry run pytest
============================================================================= test session starts ==============================================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
rootdir: /Users/username/sample
configfile: pyproject.toml
collected 1 item
tests/test_main.py . [100%]
============================================================================== 1 passed in 0.01s ===============================================================================
まとめ
- モジュールには
__init__.py
を忘れずに(テストも一つのモジュール) - srcとtestsでディレクトリを分けるときは、pythonpathを正しく設定する必要がある