- Day 79:テスト ― 「コードがちゃんと動くか、自分以外にも証明してみる」
- テストとは ― 「動いている“つもり”を、ちゃんと確認すること」
- pytestとは ― 「Pythonテストの定番ツール」
- テスト対象のコードを用意する ― 「小さな関数から始める」
- テストケースとは ― 「こういう入力なら、こういう結果になるはず」
- 正常系と異常系 ― 「うまくいくとき」と「わざと失敗させるとき」
- pytestでテストを書く ― 「コードに対して、もうひとつの目を用意する」
- 正常系・異常系をもう少し深掘りする
- Day 79ミニテンプレート ― pytest一周セット
- Day 79のまとめ ― 「テストは、未来の自分への“お守り”」
Day 79:テスト ― 「コードがちゃんと動くか、自分以外にも証明してみる」
Day 79では、実践開発で欠かせないテーマ、
- テストとは
- pytest
- テストケース
- 正常系
- 異常系
をじっくり扱っていきます。
「テスト」と聞くと、 ちょっと堅苦しいイメージがあるかもしれませんが、 開発の世界ではむしろ、
「未来の自分を助けてくれる、優しい仕組み」
という側面がとても大きいです。
テストとは ― 「動いている“つもり”を、ちゃんと確認すること」
なぜテストが必要なのか
コードを書いているとき、 こんな経験はありませんか。
- さっきまで動いていたのに、急に動かなくなった
- ちょっと修正したら、別のところが壊れた
- 「ここは大丈夫だろう」と思っていた部分が、実はバグだらけだった
人間の頭だけで「ちゃんと動いているはず」と信じるのは、 どうしても限界があります。
そこで登場するのが テスト です。
テストは一言で言うと、
「コードが期待通りに動くかどうかを、機械的にチェックする仕組み」
です。
- 入力を与える
- 出力を確認する
- 期待した結果と違えば「おかしい」と教えてくれる
という、冷静な相棒 のような存在です。
テストを書くメリット
テストを書くと、こんな良いことがあります。
- ちょっと修正しても、「他のところが壊れていないか」をすぐ確認できる
- バグを早めに見つけられる
- チーム開発で、「この機能はこう動くべき」という共通認識を持てる
- 自分のコードに対して、少し誇りが持てる
特に、Day 75までで作ってきたようなAPIやCLIアプリは、 テストがあるかどうかで 安心感がまるで違う ようになってきます。
pytestとは ― 「Pythonテストの定番ツール」
pytestの立ち位置
Pythonの世界には、いくつかテストフレームワークがありますが、 その中でもよく使われるのが、
pytest
です。
特徴をざっくり挙げると、
- インストールが簡単
- 書き方がシンプル(関数ベースで書ける)
- 実行コマンドも分かりやすい(
pytestだけ) - テストの自動検出(
test_*.pyや*_test.pyを探してくれる)
という、初心者にも優しいツールです。
pytestのインストール
まずはインストールから。
bash
pip install pytest
これで、pytest コマンドが使えるようになります。
テスト対象のコードを用意する ― 「小さな関数から始める」
例:足し算と割り算の関数
テストの練習用に、 シンプルな関数をいくつか用意してみましょう。
bash
mkdir day79_test_basic
cd day79_test_basic
bash
cat << 'EOF' > calc.py
def add(a: int, b: int) -> int:
"""
2つの整数を足し算して返します。
正常系では、単純に a + b の結果が返ります。
"""
return a + b
def divide(a: int, b: int) -> float:
"""
2つの整数を割り算して返します。
b が 0 の場合は ZeroDivisionError を送出します。
"""
return a / b
EOF
add(a, b):足し算divide(a, b):割り算(0割りは例外)
という、テストしやすい関数です。
テストケースとは ― 「こういう入力なら、こういう結果になるはず」
テストケースの考え方
テストケースは、一言で言うと、
「特定の入力に対して、期待される結果を定義したもの」
です。
例えば、add(a, b) なら、
- 入力:
a = 1, b = 2- 期待結果:
3
- 期待結果:
- 入力:
a = -1, b = 5- 期待結果:
4
- 期待結果:
などがテストケースになります。
divide(a, b) なら、
- 入力:
a = 10, b = 2→ 期待結果:5.0 - 入力:
a = 10, b = 0→ 期待結果:ZeroDivisionErrorが発生
というように、
「正常に動くパターン」と「エラーになるパターン」
の両方を考えることが大事です。
正常系と異常系 ― 「うまくいくとき」と「わざと失敗させるとき」
正常系(ハッピーなパターン)
正常系 は、
「想定通りの入力を与えたときに、期待通りの結果が返ってくるか」
を確認するテストです。
例えば add(a, b) なら、
add(1, 2)→3add(-1, 5)→4
などが正常系です。
divide(a, b) なら、
divide(10, 2)→5.0divide(9, 3)→3.0
などですね。
異常系(わざと失敗させるパターン)
異常系 は、
「おかしな入力や、境界的な入力を与えたときに、正しくエラーになるか」
を確認するテストです。
例えば divide(a, b) なら、
divide(10, 0)→ZeroDivisionErrorが発生するはず
この「エラーがちゃんと発生するか」をテストするのが、異常系です。
異常系のテストは、
- セキュリティ的にも重要(変な入力で壊れないか)
- 信頼性にも重要(予期しない動きにならないか)
という、かなり大事な役割を持っています。
pytestでテストを書く ― 「コードに対して、もうひとつの目を用意する」
テストファイルを作る
pytestでは、 test_*.py という名前のファイルにテストを書くのが一般的です。
calc.py に対するテストを、test_calc.py に書いてみましょう。
bash
cat << 'EOF' > test_calc.py
from calc import add, divide
import pytest
def test_add_normal():
"""
add 関数の正常系テストです。
いくつかの入力に対して、期待通りの結果が返るか確認します。
"""
# 1 + 2 = 3 になるはず
assert add(1, 2) == 3
# -1 + 5 = 4 になるはず
assert add(-1, 5) == 4
# 0 + 0 = 0 になるはず
assert add(0, 0) == 0
def test_divide_normal():
"""
divide 関数の正常系テストです。
割り算が正しく行われるか確認します。
"""
# 10 / 2 = 5.0 になるはず
assert divide(10, 2) == 5.0
# 9 / 3 = 3.0 になるはず
assert divide(9, 3) == 3.0
def test_divide_zero_error():
"""
divide 関数の異常系テストです。
0で割ったときに ZeroDivisionError が発生するか確認します。
"""
# divide(10, 0) を呼ぶと ZeroDivisionError が発生するはず
with pytest.raises(ZeroDivisionError):
divide(10, 0)
EOF
ここでのポイントを整理すると、
- テスト関数名は
test_から始める(pytestが自動で見つけてくれる) assertを使って「期待値」と「実際の値」を比較する- 異常系では
pytest.raises()を使って「例外が発生すること」を確認する
というところです。
テストを実行する
テストファイルができたら、 フォルダ内で pytest を実行してみます。
bash
pytest
うまくいけば、こんな感じの出力になります。
============================= test session starts =============================
collected 3 items
test_calc.py ... [100%]
============================== 3 passed in 0.03s =============================
collected 3 items:3つのテスト関数が見つかった...:3つとも成功(passed)3 passed:すべてのテストが通った
という、気持ちのいい結果です。
もしどこかにバグがあれば、 F(failed)やエラーメッセージが表示されます。
正常系・異常系をもう少し深掘りする
正常系テストで意識したいこと
正常系テストでは、
- 代表的な入力 をテストする
- 境界値(ギリギリの値)もできればテストする
ことが大事です。
例えば、add(a, b) なら、
- 小さい値
- 大きい値
- 正と負の組み合わせ
などを試しておくと、 「この関数は、だいたいどんな入力でもちゃんと動くな」と 安心しやすくなります。
異常系テストで意識したいこと
異常系テストでは、
- 明らかにおかしい入力(例:0割り、負の値、空文字など)
- 仕様上禁止されている入力
に対して、
- 正しく例外が出るか
- 変な値を返さないか
- アプリ全体がクラッシュしないか
を確認します。
異常系テストは、 「攻撃的な入力」や「予期しない使われ方」に対する防御にもつながるので、 セキュリティの観点からもとても重要です。
Day 79ミニテンプレート ― pytest一周セット
最後に、今日の内容をひとまとめにした 「pytest一周練習テンプレート」 を載せておきます。
1. テスト対象のコードを用意する
bash
mkdir day79_test_basic
cd day79_test_basic
bash
cat << 'EOF' > calc.py
def add(a: int, b: int) -> int:
"""
2つの整数を足し算して返します。
"""
return a + b
def divide(a: int, b: int) -> float:
"""
2つの整数を割り算して返します。
b が 0 の場合は ZeroDivisionError を送出します。
"""
return a / b
EOF
2. pytest をインストールする
bash
pip install pytest
3. テストファイルを作る(正常系+異常系)
bash
cat << 'EOF' > test_calc.py
from calc import add, divide
import pytest
def test_add_normal():
assert add(1, 2) == 3
assert add(-1, 5) == 4
assert add(0, 0) == 0
def test_divide_normal():
assert divide(10, 2) == 5.0
assert divide(9, 3) == 3.0
def test_divide_zero_error():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
EOF
4. テストを実行する
bash
pytest
- すべて
passedになればOK - わざとバグを入れて、
failedを体験してみるのもおすすめ
Day 79のまとめ ― 「テストは、未来の自分への“お守り”」
今日の主役は、
- テストとは何か:コードが期待通りに動くかを機械的に確認する仕組み
- pytest:Pythonテストの定番ツール
- テストケース:入力と期待結果をセットにした「確認の単位」
- 正常系:うまくいくパターンを確認するテスト
- 異常系:わざと失敗させて、正しくエラーになるかを見るテスト
でした。
テストを書くのは、 最初は少し面倒に感じるかもしれません。
でも、コードが複雑になればなるほど、
- 「テストがあるかどうか」で安心感がまるで違う
- 「テストが通っている」という事実が、心の支えになる
- 「壊しても、すぐに気づける」という自由さが生まれる
ということを、きっと実感するはずです。
テストは、 ただのチェックではなく、
「未来の自分へのお守り」
でもあります。
Day 79でその入り口に立ったことで、 これからの実践開発は、 より落ち着いて、より誇りを持って、 コードを書き進めていけるようになっていきます。
