poetryで管理しているプロジェクトにpytestを導入する(ModuleNotFoundErrorの解決方法も記載)

python-logo Python

まずはプロジェクト初期化

$ 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 ===============================================================================

まとめ

  1. モジュールには__init__.pyを忘れずに(テストも一つのモジュール)
  2. srcとtestsでディレクトリを分けるときは、pythonpathを正しく設定する必要がある
タイトルとURLをコピーしました