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

無料レッスン

テスト駆動開発の進め方

このレッスンのあとで: 失敗するテストを先に書き、通るコードを書き、整理することができる。

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

テスト駆動開発の進め方

テスト駆動開発(TDD)とは、コードを書く前に、失敗するテストを先に書く開発のやり方です。赤、緑、整理の3つの段を、小さく何度も回します。

いつも動くテストが手元にあるので、コードを変えても怖くありません。書いた直後にバグが見つかるので、直す手間も小さく済みます。

このレッスンのゴール

メモ

失敗するテストを先に書き、通るコードを書き、整理することができる。

キーワード

ことばいみ
テスト駆動開発テストを先に書いて、コードを少しずつ育てるやり方。TDD とも呼ぶ
赤(レッド)書いたばかりのテストが、失敗している状態
緑(グリーン)すべてのテストが通っている状態
リファクタリング動きを変えずに、コードを読みやすく整えること
回帰直したはずの所や、動いていた所が、また壊れること

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

赤、緑、整理を小さく回す

1回目は赤です。まだない機能のテストを1つだけ書き、失敗するのを確かめます。

2回目は緑です。そのテストが通る、いちばん簡単なコードを書きます。

3回目は整理です。テストが通ったまま、コードを読みやすくします。そして、次のテストへ進みます。

時間の文字列を分に直す関数を育てる

to_minutes("45m") が 45 を、to_minutes("2h") が 120 を返す関数を、ラボで育てます。

動かす結果は、順に 4 回出ます。最初は FAILED (failures=1)、次に OK、また FAILED (failures=1)、最後に OK です。赤、緑、赤、緑の4つが、上から順に出れば成功です。

作業用のフォルダを作る

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

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

そのフォルダへ移る

コマンド
cd ~/testing/tdd

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

中身のない関数を置く

コマンド
printf 'def to_minutes(text):\n    return 0\n' > duration.py

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

最初のテストを書く

コマンド
printf 'import unittest\nfrom duration import to_minutes\n\n\nclass TestDuration(unittest.TestCase):\n    def test_minutes_only(self):\n        self.assertEqual(to_minutes("45m"), 45)\n' > test_duration.py

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

赤: 失敗を確かめる

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

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

緑: 通る最小のコード

コマンド
printf 'def to_minutes(text):\n    return int(text[:-1])\n' > duration.py

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

緑: 通ったか確かめる

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

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

次のテストを足す

コマンド
printf '\n    def test_hours_only(self):\n        self.assertEqual(to_minutes("2h"), 120)\n' >> test_duration.py

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

赤: また失敗する

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

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

緑: 時間も分も読む

コマンド
printf 'def to_minutes(text):\n    number = int(text[:-1])\n    if text[-1] == "h":\n        return number * 60\n    return number\n' > duration.py

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

緑: 両方通る

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

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

2回目の赤が教えたこと

1回目の緑のコードは、int(text[:-1]) だけでした。45 のテストには十分でした。

次のテストを足すと、2 が返って、期待の 120 と違うので赤になりました。テストが、足りない所を教えてくれたのです。

4回目で緑に戻り、2つのテストが両方とも通っています。

よくある間違い

注意

「テストは、コードを書いたあとに書けばよい」と考える人が多くいます。先に失敗を見ていないと、そのテストが本当に働くのか分かりません。最初から通るテストは、間違いがあっても通ってしまうかもしれません。

整理はテストが守ってくれる

リファクタリングは、動きを変えずにコードを整えることです。数に名前を付けるのも、その1つです。

テストが全部通っていれば、整理のあとも通る限り、動きは変わっていません。コードを直して前の機能が壊れることを回帰と呼び、テストはそれを見張ります。

整理の前と後を比べる

コード: python
TAX_PERCENT = 10

# 整理の前: 10 という数が、式に埋まっています。
def with_tax_before(price):
    return price + price * 10 // 100

# 整理のあと: 名前を付けたので、意味が読めます。
def with_tax_after(price):
    return price + price * TAX_PERCENT // 100

# 整理の前と後で、答えが同じかを確かめます。
for price in [0, 500, 1000, 1980]:
    print(price, with_tax_before(price) == with_tax_after(price))
# TAX_PERCENT を 8 に変えると、前と後の答えが食い違います。理由を考えましょう。

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

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