pytest の基本

# pytest の基本

- [pytest の基本](#pytest-の基本)
  - [Python 仮想環境の用意](#python-仮想環境の用意)
  - [基本的な pytest コードの作成](#基本的な-pytest-コードの作成)
    - [テストコードの例](#テストコードの例)
  - [pytest の実行](#pytest-の実行)
    - [ディレクトリ内のすべての対象テストコードをテスト](#ディレクトリ内のすべての対象テストコードをテスト)
      - [実行結果](#実行結果)
    - [特定のファイルのみテスト](#特定のファイルのみテスト)
      - [実行結果](#実行結果-1)
    - [テストをパスしない場合の traceback を非表示](#テストをパスしない場合の-traceback-を非表示)
      - [実行結果](#実行結果-2)
    - [テスト実行に関する詳細情報を出力](#テスト実行に関する詳細情報を出力)
      - [実行結果](#実行結果-3)

## Python 仮想環境の用意

1. 任意のディレクトリに移動

   ```cmd
   mkdir <新規作成する任意のディレクトリ>
   cd <作成した任意のディレクトリ>
   ```

2. poetry 環境の作成

   ```poetry
   # pyproject.toml ファイル作成
   poetry init

   # 仮想環境 .venv をカレントディレクトリに作成するよう設定
   poetry config virtualenvs.in-project true

   # 仮想環境 .venv の作成
   poetry shell

   # 仮想環境のアクティベート
   source .venv/bin/activate
   ```

3. pytest のインストール

   ```poetry
   poetry add pytest
   ```

## 基本的な pytest コードの作成

pytest テストコードは以下のルールに従って作成する。

- テストコードの .py ファイル名は `test_` 接頭辞をつける、もしくは、`_test` 接尾辞をつける。

  - 例）
    - test_sample.py
    - hoge_test.py

- テストコード内のテスト関数の関数名は、`test_` 接頭辞をつける。

### テストコードの例

- テスト成功するテストコード

  ```Python:test_pass.py
  def test_passing():
    assert (1, 2, 3) == (1, 2, 3)
  ```

- テスト失敗するテストコード

  ```Python:test_fail.py
  def test_failing():
    assert (1, 2, 3) == (3, 2, 1)
  ```

- テストコードとして検出されないコード

  ```python:test_hoge.py
  # ファイル名はテスト対象であるが、関数名がテスト対象でないためテストされない
  def hoge_test():
    assert (1, 2, 3) == (1, 2, 3)

  ```

## pytest の実行

テストコードのあるディレクトリに移動して以下のコマンドを実行する。

```text
<current_dir>
├── README.md
├── poetry.lock
├── pyproject.toml
└── src
    ├── test_fail.py
    ├── test_hoge.py
    └── test_pass.py
```

### ディレクトリ内のすべての対象テストコードをテスト

```bash
pytest
```

#### 実行結果

以下のように、テスト結果がターミナルに出力されます。

どのテストメソッドのどの処理で失敗したかをすぐに特定できます。

実際にはテストをパスしなかった箇所は赤字で強調してくれるので、直感的で分かりやすいです。

```text
========================================================= test session starts =========================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
rootdir: /Users/junpei/A_Python/training_pytest
configfile: pyproject.toml
collected 2 items

src/test_fail.py F                                                                                                              [ 50%]
src/test_pass.py .                                                                                                              [100%]

============================================================== FAILURES ===============================================================
____________________________________________________________ test_failing _____________________________________________________________

    def test_failing():
>       assert (1, 2, 3) == (3, 2, 1)
E       assert (1, 2, 3) == (3, 2, 1)
E
E         At index 0 diff: 1 != 3
E         Use -v to get more diff

src/test_fail.py:2: AssertionError
======================================================= short test summary info =======================================================
FAILED src/test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)
===================================================== 1 failed, 1 passed in 0.03s =====================================================
```

### 特定のファイルのみテスト

特定のファイルを明示的に指定して、テストすることもできます。

以下のようにテストしたいファイルのパスを指定します。

```bash
pytest src/test_pass.py
```

#### 実行結果

```text
========================================================= test session starts =========================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
rootdir: /Users/junpei/A_Python/training_pytest
configfile: pyproject.toml
collected 1 item

src/test_pass.py .                                                                                                              [100%]

========================================================== 1 passed in 0.01s ==========================================================
```

### テストをパスしない場合の traceback を非表示

テストをパスしなかった場合に出力される traceback を省略するには、`--tb` オプションに `no` を指定します。

```bash
pytest --tb=no
```

#### 実行結果

以下のように、テスト結果がどのファイルで成功・失敗したかをシンプルに表示できます。

```text
========================================================= test session starts =========================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0
rootdir: /Users/junpei/A_Python/training_pytest
configfile: pyproject.toml
collected 2 items

src/test_fail.py F                                                                                                              [ 50%]
src/test_pass.py .                                                                                                              [100%]

======================================================= short test summary info =======================================================
FAILED src/test_fail.py::test_failing - assert (1, 2, 3) == (3, 2, 1)
===================================================== 1 failed, 1 passed in 0.02s =====================================================
```

### テスト実行に関する詳細情報を出力

詳細情報を出力するには、`-v` （もしくは `--verbose` 非省略）オプションを使用します。

```bash
pytest -v
```

#### 実行結果

```text
========================================================= test session starts =========================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0 -- /Users/junpei/A_Python/training_pytest/.venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/junpei/A_Python/training_pytest
configfile: pyproject.toml
collected 2 items

src/test_fail.py::test_failing FAILED                                                                                           [ 50%]
src/test_pass.py::test_passing PASSED                                                                                           [100%]

============================================================== FAILURES ===============================================================
____________________________________________________________ test_failing _____________________________________________________________

    def test_failing():
>       assert (1, 2, 3) == (3, 2, 1)
E       AssertionError: assert (1, 2, 3) == (3, 2, 1)
E
E         At index 0 diff: 1 != 3
E
E         Full diff:
E           (
E         +     1,
E         +     2,...
E
E         ...Full output truncated (4 lines hidden), use '-vv' to show

src/test_fail.py:2: AssertionError
======================================================= short test summary info =======================================================
FAILED src/test_fail.py::test_failing - AssertionError: assert (1, 2, 3) == (3, 2, 1)
===================================================== 1 failed, 1 passed in 0.03s =====================================================
```