pytest の使い方がときどきよくわからなくなるので備忘録。
ディレクトリ構成
- 単体テストは tests/test_hello.py に記述
- hello/hello.py で Hello Class を定義
- hello/main.py で Hello Class インスタンスを作成,say メソッドを実行した際に
Hello, World!
を print
├── hello
│ ├── __init__.py
│ ├── hello.py
│ └── main.py
├── poetry.lock
├── pyproject.toml
└── tests
└── test_hello.py
Poetry のインストール
curl -sSL https://install.python-poetry.org | python3 -
pyproject.toml
poetry init
を実行するか,エディタ等で pyproject.toml を作成します。
pyproject.toml
[tool.poetry]
name = "hello"
version = "0.1.0"
description = "getting started with pytest"
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.11"
pytest = "^7.4.3"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
hello = "hello.main:main"
poetry init
を使った場合は,poetry add pytest
も実行する必要があります。
poetry run hello で hello/main.py の main 関数を実行します。
name = "hello"
と hello ディレクトリで名前に不整合があると,以下の No module
エラーが発生します。
from hello.hello import Hello
E ModuleNotFoundError: No module named 'hello'
poetry install / update
poetry install を実行します。
$ poetry install
Updating dependencies
Resolving dependencies... (0.1s)
No dependencies to install or update
Writing lock file
Installing the current project: hello (0.1.0)
テストコードを記述
Hello Class インスタンスを作成,greeting メソッドを実行した際に Hello, World!
が返されることを期待します。
test_hello.py
import pytest
from hello.hello import Hello
def test_hello():
hello = Hello()
assert hello.greeting == "Hello, World!"
pytest を実行
$ poetry run pytest -v
========================= test session starts ==========================
platform darwin -- Python 3.11.6, pytest-7.4.3, pluggy-1.3.0 -- /Users/foo/Library/Caches/pypoetry/virtualenvs/hello-7y5vTctl-py3.11/bin/python
cachedir: .pytest_cache
rootdir: /Users/foo/lab
collected 0 items / 1 error
================================ ERRORS ================================
_________________ ERROR collecting tests/test_hello.py _________________
ImportError while importing test module '/Users/foo/lab/tests/test_hello.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_hello.py:2: in <module>
from hello.hello import Hello
E ImportError: cannot import name 'Hello' from 'hello.hello' (/Users/foo/lab/hello/hello.py)
======================= short test summary info ========================
ERROR tests/test_hello.py
!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!
=========================== 1 error in 0.03s ===========================
まだ何も Class を記述していないので当然テストに失敗します。
Hello Class を記述
以下のように Hello Class を定義します。
hello/hello.py
class Hello:
def __init__(self):
self.greeting = "Hello, World!"
def say(self):
print(self.greeting)
テストを再実行
$ poetry run pytest -v
========================= test session starts ==========================
platform darwin -- Python 3.11.6, pytest-7.4.3, pluggy-1.3.0 -- /Users/foo/Library/Caches/pypoetry/virtualenvs/hello-7y5vTctl-py3.11/bin/python
cachedir: .pytest_cache
rootdir: /Users/foo/lab
collected 1 item
tests/test_hello.py::test_hello PASSED [100%]
========================== 1 passed in 0.00s ===========================
テストをパスしました。
main.py を記述
メインのコードを記述します。お約束の Hello, World!
を print するだけです。
hello/main.py
from hello.hello import Hello
def main():
greeting = Hello()
greeting.say()
poetry run
で期待通りの結果が得られました。
$ poetry run hello
Hello, World!