としていました。
しかし、
> **「動いた」と「正しい」は違います。**
例えばCSV変換ツールなら、
```text id="m76hgi"
UTF-8 → OK
CP932 → ?
空ファイル → ?
0バイト → ?
存在しない → ?
列不足 → ?
不正データ → ?
これがSTEP 6で作りたい状態です。
---
# 6-2. テストコードとは
例えば、
```python id="n8hpwa"
def add(a, b):
return a + b
と確認できます。
これをコードにすると、
```python id="sqh5xe"
def test_add():
assert add(2, 3) == 5
を自動化したものです。
---
# 6-3. assertとは
テストでは頻繁に、
```python id="r1aiv6"
assert actual == expected
actualはexpectedと同じであるはず
なら、
```text id="lxt10a"
result = 5
expected = 5
5 == 5
↓
PASS
なら、テストが失敗します。
---
# 6-4. pytestとは
pytestはPythonで広く使われているテストフレームワークです。
例えば、
```text id="zzllh6"
project/
│
├─ main.py
├─ csv_utils.py
│
└─ tests/
└─ test_csv_utils.py
を実行すると、テストを探して実行してくれます。
最初は、
> **pytest = Pythonプログラムを自動チェックする仕組み**
くらいの理解で十分です。
---
# 6-5. pytestを準備する
学習用Python環境で、
```powershell id="xvm88u"
python -m pip install pytest
です。
実行も最初は、
```powershell id="2v8f96"
python -m pytest
csv_utils.py
に、
があるとします。
`tests/test_csv_utils.py` を作ります。
```python id="h5ifpw"
from csv_utils import convert_name
def test_convert_name():
result = convert_name(" Tanaka ")
assert result == "Tanaka"
成功すれば、
```text id="9qx0cy"
passed
のように複数のケースがあります。
重要なのは、
> **一つ動いたから全部動く**
とは考えないことです。
---
# 6-8. 正常系とは
まず最も普通の使い方です。
例えば、
```text id="2ev7gl"
input.csv
name,department
Tanaka,Sales
Suzuki,Development
assert len(result) == 3
のようになります。
---
# 6-9. 「正常に終了した」だけでは足りない
例えば、
```text id="uvd2cl"
python main.py
Exit Code 0
かもしれません。
だからテストでは、
```text id="k8dr8d"
実行できた?
+
件数は正しい?
+
値は正しい?
+
形式は正しい?
があります。
Pythonでは `FileNotFoundError` が発生する設計なら、pytestでそのこと自体を確認できます。
```python id="ptks3q"
import pytest
def test_missing_file():
with pytest.raises(FileNotFoundError):
read_csv("not_found.csv")
FileNotFoundErrorが発生すればPASS
のように考えます。
Codexに、
```text id="i9wcr3"
read_csv()について、
テストすべきケースを洗い出してください。
まだテストコードは作成しないでください。
正常系と異常系に分けて、
各ケースについて
・入力
・期待結果
・なぜ必要か
を説明してください。
ではなく、
```text id="esjgqx"
Explore
↓
Test Plan
↓
人間が確認
↓
Test Code
CSVは最大1000件まで処理する
が重要です。
なぜならバグは、
```text id="85g5vb"
普通の値
など、**境界付近**で起きやすいからです。
---
# 6-13. CSVツールの境界値
CSVなら例えば、
```text id="8cy27v"
0行
1行
ヘッダーのみ
データ1件
空文字
列数1
列数最大
非常に長い文字列
どこが境界なのかを考える習慣
人間が思いつかなかったケースを発見することがあります。
---
# 6-15. テストをCodexに作らせる
Test Planを確認したら、
```text id="upmht5"
先ほどのTest Planから、
まず正常系のpytestを作成してください。
対象:
csv_utils.py
テストはtestsディレクトリに作成してください。
まだ本体コードは変更しないでください。
作成後、
追加したテストケースを説明してください。
テスト作成のために本体コードまで勝手に直させない
とします。
例えば、
```text id="whk1ap"
12 tests collected
10 passed
2 failed
2件失敗した → すぐ本体を修正
ではありません。
むしろ、
```text id="m7qzbb"
テスト失敗
↓
問題を発見できた
なら、
> 「CP932対応に問題がある」
ことを自動的に発見できたわけです。
テストの価値が出ています。
---
# 6-18. ただし「テストが間違っている」こともある
ここがAI時代には特に重要です。
Codexが作ったテストだから正しいとは限りません。
例えば仕様が、
```text id="95fvt3"
空CSV
↓
空リストを返す
と勝手に想定してテストを書くかもしれません。
その場合、
```text id="yl3tvl"
本体コードが間違い
ではなく
テスト仕様が間違い
とします。
これがデバッグです。
---
# 6-20. Debuggingとは
Debugging(デバッグ)は、
> **問題の原因を調査して取り除く作業**
です。
大事なのは、
```text id="mlbjrx"
エラー
↓
とにかく修正
という順番です。
STEP 4のExploreと同じ考え方ですね。
---
# 6-21. エラーメッセージを読ませる
例えばpytestで、
```text id="1bdxkj"
FAILED tests/test_csv_utils.py::test_cp932
とCodexに依頼します。
---
# 6-22. テストを先に作る考え方
例えば、新しく、
> CP932対応を追加する
とします。
従来なら、
```text id="b5pkjz"
コード変更
↓
動かす
↓
確認
という進め方もできます。
これは後々、テスト駆動的な開発を理解するときにも役立ちます。
STEP 6では厳密なTDDを覚える必要はありません。
**「実装前に完成条件をテストとして書ける」**
という感覚をつかめれば十分です。
---
# 6-23. Red → Green
簡単に表すと、
```text id="8qrptm"
新しいTest
↓
FAIL
↓
RED
↓
実装・修正
↓
PASS
↓
GREEN
最初にFAILすることを確認する
という疑問が出ます。
---
# 6-24. 回帰テスト
STEP 4でも出てきたRegressionです。
例えば、
```text id="cbl59k"
Version 1
UTF-8対応
↓
test_utf8 PASS
Version 2
CP932対応追加
↓
test_cp932 PASS
でも
test_utf8 FAIL
します。
これが**Regression Test(回帰テスト)**の重要な役割です。
---
# 6-25. バグを直したらテストを残す
例えば、
> 空CSVでクラッシュする
というバグを発見したとします。
修正だけすると、
```text id="ec4wzq"
Bug
↓
Fix
↓
半年後
↓
別変更
↓
同じBug復活
とします。
すると将来、
```text id="fud3h1"
誰かが変更
↓
pytest
↓
昔のBugが復活
↓
FAIL
だけではありません。
```text id="qup4r2"
バグ
↓
再現条件を理解
↓
Testにする
↓
Regression Testとして保存
一度経験したバグを二度と見逃しにくくする
fixture
という言葉が出てきます。
といった準備が必要になります。
fixtureは簡単に言えば、
> **テストに必要な準備を再利用する仕組み**
です。
STEP 6ではfixtureを高度に使う必要はありません。
まずはpytestの `tmp_path` が便利です。
---
# 6-28. tmp_path
テストのために、
```text id="3q2kwj"
test.csv
test2.csv
test3.csv
tmp_path
を使えます。 csv_file.write_text(
"name,department\nTanaka,Sales",
encoding="utf-8"
)
result = read_csv(csv_file)
assert len(result) == 2
テスト専用の一時領域でファイルを作れます。
CSV処理のテストではかなり便利です。
---
# 6-29. parametrize
例えば、
```text id="g8pfpj"
UTF-8
CP932
UTF-8 BOM
parametrize
を使ってまとめる方法があります。
とできます。
ただし、最初から無理に使う必要はありません。
まず、
```text id="muczb9"
test_utf8()
test_cp932()
test_utf8_bom()
と聞いてみるのがおすすめです。
---
# 6-30. Mockはこの段階では深入りしない
テストを調べていると、
```text id="1c7iys"
Mock
Monkeypatch
Patch
くらいを中心にします。
Mockは必要になったときに学べば十分です。
---
# 6-31. テストしやすいコードとは
ここで面白いことが起きます。
例えば、
```python id="gdp00c"
def process():
# GUIから値取得
# CSV読込
# 文字コード判定
# データ変換
# ファイル保存
# MessageBox表示
と分かれていると、各関数を個別にテストできます。
つまり、
> **テストを書こうとすると、コード設計の問題も見えてくる**
わけです。
STEP 4のリファクタリングとつながります。
---
# 6-32. Unit Testとは
Unit Test(単体テスト)は、
> **小さな機能単位を個別に確認するテスト**
です。
例えば、
```text id="4lhz6n"
detect_encoding()
↓
Unit Test
convert_row()
↓
Unit Test
normalize_name()
↓
Unit Test
と依頼できます。
全部テストする必要はありません。
**重要な処理からテストする**ことを学びます。
---
# 6-34. テストの品質もReviewする
Codexがテストを20個作ったとしても、
> 20個あるから安心
とは限りません。
例えば全部、
```text id="ynbt42"
正常なUTF-8
正常なUTF-8
正常なUTF-8
とします。
---
# 6-35. テスト数より「何を守っているか」
重要なのは、
```text id="euhkrt"
100 tests
です。
例えば、
```text id="hpuobc"
test_utf8
↓
UTF-8読込を守る
test_cp932
↓
CP932読込を守る
test_empty_csv
↓
空CSV処理を守る
test_missing_file
↓
不存在時の動作を守る
これでかなり実際の開発に近づきます。
---
# 6-37. Commit前にpytest
自分のルールとして、
```text id="1upz1z"
Commitする前に
git status
↓
git diff
↓
pytest
↓
全部PASS?
↓
git add
↓
git diff --staged
↓
commit
程度でした。
STEP 6以降は、
```text id="tbsxbm"
変更後に既存のpytestをすべて実行してください。
今回追加した機能について
必要なテストも追加してください。
既存テストを変更する必要がある場合は、
変更理由を説明してください。
すべてのテスト結果を報告してください。
を体験します。
実習:
```text id="m37dpa"
① pytest導入
② tests/作成
③ test_csv_utils.py作成
④ 正常系テスト1個
⑤ pytest実行
⑥ 本体をわざと変更
⑦ FAILを確認
⑧ git restore
⑨ pytest
⑩ PASSを確認
テストが壊れたコードを検出する
| 種類 | ケース | 期待 |
|---|---|---|
|
正常系
|
UTF-8 | 正常読込 |
|
正常系
|
CP932 | 正常読込 |
|
正常系
|
1件 | 正常処理 |
|
境界値
|
空CSV | 仕様通り |
|
境界値
|
ヘッダーのみ | 仕様通り |
|
異常系
|
ファイル不存在 | 所定のエラー |
|
異常系
|
不正データ | 所定の処理 |
そして、
```powershell id="p9rbmc"
python -m pytest
と依頼します。
その後、
```text id="9xjjwd"
修正Plan
↓
人間が確認
↓
Fix
↓
pytest
空CSVでクラッシュする
この一連をCodexと行います。
---
# 6-43. 4日間の学習計画
| 日 | テーマ | 実習 | 到達目標 |
| ------- | ----------- | ------------------ | ---------------- |
| **1日目** | pytest基礎 | assert、PASS/FAIL | 自動テストを実行できる |
| **2日目** | Test Design | 正常系・異常系・境界値 | テストケースを設計できる |
| **3日目** | Debug | FAIL→原因調査→修正 | テストから不具合を追跡できる |
| **4日目** | Regression | Bug→Test→Fix→全Test | 過去の不具合をテスト資産にできる |
---
# 6-44. STEP 6で覚える用語
| 用語 | 意味 |
| ------------------- | ----------------- |
| **pytest** | Pythonのテストフレームワーク |
| **Test Case** | 一つのテスト条件 |
| **assert** | 実際値と期待値を確認 |
| **Unit Test** | 小さな機能単位のテスト |
| **Normal Case** | 正常系 |
| **Error Case** | 異常系 |
| **Boundary Value** | 境界値 |
| **Regression** | 変更で既存機能が壊れること |
| **Regression Test** | 過去・既存機能を守るテスト |
| **fixture** | テストの準備を共通化 |
| **tmp_path** | pytestの一時ディレクトリ |
| **Debugging** | 不具合原因を調査・修正する作業 |
特に、
**Normal / Boundary / Error / Regression**
の4種類を意識してください。
---
# 6-45. STEP 6以降のCodex基本指示
ここまで来ると、Codexへの依頼もかなり実践的になります。
```text id="vv0m4m"
【目的】
CSV文字コード処理を改善する。
【Explore】
現在の実装と関連する既存テストを調査する。
まだ変更しない。
【Plan】
変更内容と、
追加・変更すべきテストを計画する。
まだ実装しない。
【Edit】
承認したPlanだけを実装する。
【Test】
正常系
境界値
異常系
Regression
を考慮する。
【Verify】
関連テストだけでなく
既存pytestをすべて実行する。
【Review】
git diffを確認し、
目的外の変更がないか確認する。
【Report】
・変更ファイル
・追加テスト
・実行コマンド
・PASS数
・FAIL数
・未確認事項
を報告する。
まで担当する開発Agentに近づきます。
---
# 6-46. STEP 6確認問題
**Q1.** 「プログラムが実行できた」と「正しく動作した」の違いは?
**Q2.** 正常系・異常系・境界値とはそれぞれ何でしょう?
**Q3.** pytestがFAILしたとき、なぜすぐ本体コードを修正してはいけないのでしょう?
**Q4.** テストコード自体が間違っている可能性を考える必要があるのはなぜでしょう?
**Q5.** Regression Testは何のためにありますか?
**Q6.** バグ修正時に「再現テスト → Fix」とするメリットは?
**Q7.** なぜテスト数だけで品質を判断できないのでしょう?
**Q8.** Commit前にpytestを実行するメリットは?
---
# 6-47. STEP 6 合格実習
最後はCSV変換ツールに対して、Codexを使って次のテスト環境を作ります。
```text id="tfb01q"
CSV変換ツール
│
├─ UTF-8
├─ CP932
├─ 空CSV
├─ ヘッダーのみ
├─ ファイル不存在
└─ 不正データ
↓
pytest
↓
PASS / FAIL
テスト全部作って
まで行います。
さらに、正常なコードを**わざと1か所壊してpytestを実行**してください。
```text id="qfgwjp"
正常コード
↓
意図的にBug
↓
pytest
↓
FAIL
↓
「テストがBugを発見した」
↓
git restore
↓
pytest
↓
PASS
テストは「動くことを確認するもの」だけではなく、「将来コードを壊したときに教えてくれる安全装置」
そしてここで、次の問題が出てきます。
毎回Codexへ、
```text id="ey6j2w"
Python 3.xを使って
既存機能を壊さず
pytestを全部実行して
GUIを勝手に変更せず
外部ライブラリを勝手に追加せず
……
アンソロピックのIPO目論見書の件 KIM… 2026.10.02
Microsoft Foundry Localを使って NPU付… 2026.09.29
ClaudeCodeもCodexもGoogle AIも全部やめ… 2026.09.28
PR
Calendar
Category