クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

単体テストの書き方

このレッスンのあとで: アサーションを使って、単体テストを書くことができる。

55分のレッスンコマンド7件毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

単体テストの書き方

単体テストとは、関数のような小さな部品を1つだけ取り出して、期待どおりの値を返すかを自動で確かめるテストです。Python には、そのための道具が最初から付いています。

一度書けば、コードを直すたびに数秒で全部を確かめ直せます。手で試す時間が、ほとんどなくなります。

このレッスンのゴール

メモ

アサーションを使って、単体テストを書くことができる。

キーワード

ことばいみれい
アサーション期待する値と実際の値を比べる1行assert result == 360
準備、実行、確認テストを書く3つの段。英語では Arrange、Act、Assert
テストランナーテストを探して動かし、結果をまとめるプログラム
unittestPython に付いている、テストの標準の道具
期待値仕様から先に決めた、正しい結果の値

学生が入力するセルは、このプレビューでは空白です。

テストは準備、実行、確認の3段

単体テストは、いつも3つの段でできています。

準備で、入力の値を決めます。実行で、調べたい関数を呼びます。確認で、結果が期待した値かを比べます。

確認に使う1行がアサーションです。Python では assert の後ろに、成り立つはずの式を書きます。

3段で書いた最初のテスト

コード: python
def total_price(price, count):
    return price * count

# 準備: 値段と個数を決めます。
price = 120
count = 3
# 実行: 調べたい関数を呼びます。
result = total_price(price, count)
# 確認: 期待する値と比べます。
assert result == 360
print("合格です")
# 360 を 361 に変えて、もう一度実行しましょう。

端末は unittest、課題は assert

このレッスンでは、書き方を2つ使い分けます。

ラボの端末では、Python に付いている unittest を使います。課題の自動採点では、素の assert で書いた def test_...(): の形を使います。

2つは同じ考えで、書き方が違うだけです。

unittest でテストを動かす

unittest のテストは、TestCase を受け継ぐクラスに、名前が test_ で始まるメソッドとして書きます。

self.assertEqual(実際の値, 期待値) が、2つの値を比べます。

ファイル名を test_ で始めて、python3 -m unittest と打つと、テストランナーがすべてを探して動かします。

作るテストファイルの中身

コード: python
import unittest
from shop import total_price


class TestShop(unittest.TestCase):
    def test_three_pens(self):
        self.assertEqual(total_price(120, 3), 360)

    def test_zero_pens(self):
        self.assertEqual(total_price(120, 0), 0)


if __name__ == "__main__":
    unittest.main()

作業用のフォルダを作る

コマンド
mkdir -p ~/testing/unit

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

そのフォルダへ移る

コマンド
cd ~/testing/unit

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

調べる関数を書く

コマンド
printf 'def total_price(price, count):\n    return price * count\n' > shop.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

テストファイルを書く

コマンド
printf 'import unittest\nfrom shop import total_price\n\n\nclass TestShop(unittest.TestCase):\n    def test_three_pens(self):\n        self.assertEqual(total_price(120, 3), 360)\n\n    def test_zero_pens(self):\n        self.assertEqual(total_price(120, 0), 0)\n\n\nif __name__ == "__main__":\n    unittest.main()\n' > test_shop.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

テストを動かす

コマンド
python3 -m unittest 2>&1 | tail -n 1

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

最後の行が OK なら全部合格

最後の行は OK と出ます。2つのテストが両方とも合格した、という意味です。

実際の画面には、その上に実行にかかった時間も出ます。時間は毎回違うので、ここでは最後の1行だけを見ています。

関数をわざと壊す

コマンド
printf 'def total_price(price, count):\n    return price + count  # wrong\n' > shop.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

もう一度動かす

コマンド
python3 -m unittest 2>&1 | grep AssertionError

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

失敗の知らせを読む

出力は、AssertionError: 123 != 360 と AssertionError: 120 != 0 の2行です。

左の数が実際の値、右の数が期待値です。120 と 3 を足して 123 になったと、すぐ分かります。

テストが2つとも落ちたので、最後の行は FAILED (failures=2) になります。

よくある間違い

注意

「関数を動かして出た値を、そのまま期待値にすればよい」と考える人が多くいます。それでは、間違った答えを正解として固めてしまいます。期待値は、仕様から先に決めましょう。

このラボとソースについて: 毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。