- TDDとは
- TDD開発の流れ
- TDDがもたらす影響
- プログラミングの流れ
- 使用するフレームワーク、pytestについて
- サンプルプロジェクト
- 開発要件1:レッド
- 開発要件1:グリーン
- 開発要件1:リファクタリング
- TDDの批評
- TDDが運用されたことで解決した問題
- 総括
- 参考リンク集
「動作する綺麗なコード」をゴールとした考え方です。
- テストリストを作成する
- 新たなテストコードを書く
- 自動化されたテストが失敗した時のみ、新しいコードを書く
- 重複を削除する
- 有機的な設計
- テストを高頻度で回すために、迅速に応答する開発環境が構築される
- 凝集度が高く、結合度の低い部品で構成された設計になりやすい
- レッド:動作しない、コンパイルすら通らないテストを書く
- グリーン:テストを迅速に動作させる。罪深いことをしても良い
- リファクタリング:テストを通すために重複を全て削除する
pytestは、小さなテストだけでなく、アプリケーションやライブラリの複雑な機能テストの作成をサポートするライブラリです。 https://docs.pytest.org/en/stable/
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
あなたは多国通貨のレポートを出力するアプリ開発を担当するエンジニアです。 下記要件の開発を担当しました。
- 単一通貨に対してかけ算ができる
- 2つの通貨の足し算ができる(TBA) サンプルリポジトリ
単一通貨に対して掛け算するためのテストコードを書く。
# tests/test_doller.py
from src.money import Dollar
def test_times():
five_dollar: Dollar = Dollar(5)
five_dollar.times(2)
assert five_dollar.amount == 10
if __name__ == '__main__':
test_times()
テストコードを通すために、main.moneyを書く。テストを通すために悪魔の実装をする。
# main/money.py
class Dollar:
def __init__(self, amount: int):
# テストを通すための悪魔の実装
self.amount = 10
def times(self, times: int):
pass
# main/money.py
class Dollar:
def __init__(self, amount: int):
self.amount = amount
def times(self, times: int):
# テストを通すための悪魔の実装
self.amount = 5 * 2
# main/money.py
class Dollar:
def __init__(self, amount: int):
self.amount = amount
def times(self, times: int):
# テストを通すための悪魔の実装
self.amount *= times
TDDはあくまで「動作する綺麗なコード」を書くことに焦点を向けたプラクティスであるため、銀の弾丸ではないです。 特に、TDDのプラクティス上、ユニットテストが多くなる、テストしやすい単位に細分化、間接化されるため、アーキテクチャが複雑になる、結合テストが軽視されやすくなるといったデメリットが挙げられます。 https://twop.agile.esm.co.jp/what-practice-should-be-remain-if-you-stop-tdd-239071f7102e
これに対して、TDDを考案した方はTDDの布教によって解決された問題は以下だと、facebookで発言しております。
- 過剰性能(Over-engineering)
- インタフェースと実装の分離
- ドキュメンテーション
- APIフィードバック
- 論理エラー
- 大きな問題
- プログラマ同士の問題共有
- プログラムが期待通りに動作している事を確認 https://www.facebook.com/notes/kent-beck/rip-tdd/750840194948847
- TDDは「動作する綺麗なコード」を書くことに焦点を向けたプラクティス
- レッド→グリーン→リファクタリングの流れ
- TDDのメリットデメリットは色々議論されているため、調べると面白かったです
- 色々なプラクティスを試した上で、プロジェクトや自分に合った開発プラクティスを考えて提唱していけたら、エンジニアとしてのレベルも高まるのかなと思いました
- testing vs checking
- testing and checking refined
- doctestの公式リンク
- doctestとpytest等の使い分け
- pytestの紹介記事
- TDDの批判まとめ
- TDD is dead. Long live testing.
doctestとは、対話的 Python セッションのように見えるテキストを探し出し、セッションの内容を実行して、そこに書かれている通りに振舞うかを調べるモジュールです。
def factorial(n:int):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()