Pythonでテストを書き始めると、必ず出てくるのがassert文です。
見た目は短いので、なんとなく使えてしまいますが、読みやすいテストを書くには、何を確認しているのかが伝わる書き方を意識する必要があります。
この記事では、pytestのassert文に絞って、期待値の確認方法、失敗したときの読み方、実務でつまずきやすいポイントを初心者向けに解説します。
pytestの全体像を先に知りたい方は、以下の記事もあわせて読むと理解しやすいです。 【関連記事】pytest入門|Pythonでテストを書く基本を初心者向けに解説
pytestのassert文とは¶
pytestのassert文は、プログラムの結果が期待どおりかを確認するために使います。
たとえば、足し算の関数に2と3を渡したら5が返ってほしい、という期待をコードで表せます。
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
このテストでは、add(2, 3)の結果が5なら成功します。違う値が返れば、pytestはテストを失敗として教えてくれます。
つまりassertは、期待値と実際の結果を比べるための合図です。難しそうに見えても、最初の役割はとてもシンプルです。
pytestのassertが読みやすい理由¶
assert自体はpytest専用ではありません。Pythonにもともと用意されている構文です。
それでもpytestでassertがよく使われるのは、失敗したときの表示が読みやすいからです。pytestはassert式の中間値を詳しく表示してくれるため、どこが違ったのかを追いやすくなります。
def test_total_price():
price = 1000
tax = 100
discount = 50
assert price + tax - discount == 1200
この例では、実際の計算結果は1050なので失敗します。pytestでは、単に失敗したと出るだけでなく、式の中身を見ながら原因を探せます。
エラー文が苦手な初心者にとって、これはかなり助かるポイントです。赤い表示を見ると焦りますが、pytestのメッセージは修正のヒントだと考えると読みやすくなります。
assert文で確認できること¶
assertは、値が同じかどうかを見るだけではありません。数値、文字列、リスト、真偽値など、Pythonでよく使う値を確認できます。
代表的な書き方を整理すると、次のようになります。
| 確認したいこと | 書き方の例 | 使う場面 |
|---|---|---|
| 値が等しいか | assert result == 10 |
計算結果や戻り値の確認 |
| Trueか | assert user.is_active |
条件が成立しているかの確認 |
| Falseか | assert not user.is_deleted |
条件が成立していないことの確認 |
| 要素を含むか | assert "apple" in fruits |
リストや文字列の確認 |
| 長さが合っているか | assert len(items) == 3 |
件数の確認 |
テストを読む人が、何を確認しているのかすぐ理解できる書き方を選びましょう。
等しいことを確認する¶
もっとも基本になるのは、値が等しいかを確認するassertです。関数の戻り値を確認するときによく使います。
def get_full_name(first_name, last_name):
return f"{last_name} {first_name}"
def test_get_full_name():
assert get_full_name("太郎", "山田") == "山田 太郎"
このテストは、名前の順番とスペースが期待どおりかを確認しています。文字列は1文字違うだけでも失敗します。
メッセージ、URL、ファイル名などの確認でもよく使う形です。初心者のうちは、まずこの形に慣れるだけでも十分です。
TrueやFalseを確認する¶
真偽値を返す関数では、== Trueや== Falseと書きたくなるかもしれません。動きますが、Pythonでは次のように書くほうが自然です。
def is_adult(age):
return age >= 18
def test_is_adult():
assert is_adult(20)
def test_is_not_adult():
assert not is_adult(15)
短いですが、意味ははっきり伝わります。20歳なら成人、15歳なら成人ではない、という仕様がそのまま読めます。
読みやすいassert文を書くコツ¶
assertを書くとき、期待値を左に置くか、実際の値を左に置くかで迷う人もいます。pytestではどちらでも動きますが、私は実務では実際の値を左、期待値を右に置くことが多いです。
assert calculate_total(1000, 100) == 1100
この形だと、関数を実行した結果が1100になるべきだと自然に読めます。チームにルールがある場合は、そのルールに合わせれば大丈夫です。
1つのテストで確認しすぎない¶
初心者がやりがちな失敗に、1つのテストで多くのことを確認しすぎるというものがあります。assertが10個も20個も並ぶと、失敗したときに何のテストだったのか見えにくくなります。
def test_user_name_is_created():
user = create_user("山田太郎", 30)
assert user["name"] == "山田太郎"
確認したい振る舞いごとに分けると、テスト名もassertも読みやすくなります。私の経験でも、テストは書く時間より、あとで読む時間のほうが長いです。
途中の値に名前をつける¶
長い式をそのままassertに書くと、失敗したときに読みにくくなります。そんなときは、途中の値を変数に入れるとわかりやすくなります。
def test_total_price_with_tax():
item_price = 1000
tax_rate = 0.1
total_price = item_price + int(item_price * tax_rate)
assert total_price == 1100
total_priceという名前があるだけで、何を確認しているのか見えやすくなります。テストコードは、少し冗長なくらいのほうが後から助かることが多いです。
assertが失敗したときの読み方¶
テストが失敗すると、最初は少し焦ります。でもpytestの失敗メッセージは、慣れるとかなり親切です。
def test_discount_price():
price = 1000
discount = 200
assert price - discount == 900
実際の計算結果は800なので、このテストは失敗します。見るべきポイントは、どのテストが失敗したのか、どのassertで止まったのか、実際の値はいくつだったのかの3つです。
全部の英語を完璧に読もうとしなくて大丈夫です。まずはE assertで始まる行を探して、期待値と実際の値のズレを見ましょう。
エラー文は敵ではありません。どこを直せばよいか教えてくれるメモです。
比較の種類を使い分ける¶
assertでは、Pythonの比較演算子をそのまま使えます。ここを理解すると、テストで表現できることが増えます。
Noneと小数の比較¶
値が存在しないことを確認するときは、Noneを使います。Noneの確認では、== Noneではなくis Noneを使うのが一般的です。
def test_find_user_not_found():
user = find_user("unknown@example.com")
assert user is None
小数を扱うテストでは、完全一致に注意が必要です。コンピューターの内部表現の都合で、0.1 + 0.2が直感どおりぴったり0.3にならないことがあります。
import pytest
def test_float_with_approx():
assert 0.1 + 0.2 == pytest.approx(0.3)
このようなケースでは、pytestのapproxを使うと、多少の誤差を許容して比較できます。金額のように誤差が困る値ではDecimalも検討しましょう。
実務でよくあるassertの失敗例¶
assert文はシンプルですが、実務では意外なところで読みづらくなります。次のassertは動きますが、読み手には少し不親切です。
def test_items():
items = get_items()
assert items
これはitemsが空ではないことを確認しています。ただ、件数が重要ならlen(items) == 3のように具体的に書いたほうが明確です。
テスト名とのズレにも注意しましょう。ログインできることを確認するテストなのに、ステータスコードだけを見ているケースは現場でもよくあります。
def test_user_can_login():
response = login("taro@example.com", "password")
assert response.status_code == 200
ステータスコード200だけでは、本当にログイン状態になったかまではわからないかもしれません。テスト名は約束で、assert文はその約束を確かめる場所です。
実務でassert文を使うときの考え方¶
実務でテストを書くときは、正しいかどうかだけでなく、失敗したときにすぐ直せるかも大切です。動くテストでも、原因が追いにくいテストはあとから負担になります。
レビューでよく見るのは、assertの条件が曖昧なケースです。たとえばassert responseだけでは、レスポンスが存在することしかわかりません。
本当に確認したいのが成功ステータスなら、assert response.status_code == 200のほうが親切です。返却データの件数が重要なら、assert len(response.json()["items"]) == 3のように、期待を具体的に書いたほうが読み手に伝わります。
テストは、未来の自分やチームメンバーへのメッセージでもあります。なぜそのassertを書いたのかが自然に伝わると、修正や機能追加の不安がかなり減ります。
また、初心者のうちは完璧なテストを目指しすぎなくて大丈夫です。まずは重要な関数に1つassertを書き、失敗したときの表示を読むところから始めると、自然に感覚がつかめます。
assert文と例外テストの関係¶
期待値の確認は、戻り値だけではありません。不正な入力を受け取ったときにエラーになることも、立派な期待です。
ただし、例外の確認では通常のassertだけでなく、pytestのraisesを使います。
import pytest
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)
このテストは、0で割ろうとしたときにValueErrorが発生することを確認しています。入力チェック、権限チェック、ファイルが存在しない場合などで役立ちます。
まとめ¶
pytestのassert文は、Pythonテストの中心になる基本機能です。書き方はシンプルですが、期待値の置き方、比較の種類、失敗メッセージの読み方を知っているだけで、テストの品質は大きく変わります。
初心者のうちは、まず戻り値が期待どおりかを確認するところから始めれば大丈夫です。慣れてきたら、TrueやFalse、小数、None、例外など、確認できる範囲を少しずつ広げていきましょう。
テストは、コードを書く人を責めるためのものではありません。未来の自分が安心して修正するための味方です。
小さなassertを1つ書くことから始めてみてください。
最初の1本は短くて構いません。小さく書いて、少しずつ育てていく感覚で続けましょう。
ここまでお読みいただきありがとうございました。