テスト駆動開発で実装したい。土日に温めてました。
テスト駆動開発で実装する際に、気をつけている点をまとめつつ。
テスト駆動開発(TDD)とは
真っ先にテストの実装を行う開発手法というと言葉が足りていない。小さなサイクルを回して、実装を行っていく開発プロセス。
基本的に1サイクル6ステップがある。
目的の関数を実装する際に、
1.テストを実装する
2.テストに失敗するような関数を実装する
3.テストに失敗していることを確認する
4.テストが通るように修正する
5.テストが通ったことを確認する
6.コードを修正する(重複・モジュール化等)
2.に戻る
プロセスごとに大まかな名前付けがされており、red、green、refactor となる。
red では2~3までのプロセス、テスト結果が red だからという単純な理由ではありますが。green は、4~5、refactor は6のプロセスを指します。
メリットについて
1.シンプルな実装
2.デバッグ容易性
3.疎結合を意識した実装
1.シンプルな実装
テスト駆動開発は、テストとテストをパスするための最小限の実装を行っていくスタイルをとっています。テストを実装する際に関数の最終的な出力は自明になり、テストが関数の役割をある程度規定するという立ち位置になります。結果的に不要な実装は省かれます。
2.デバッグ容易性
また、ユニットテストを繰り返していきながら、リファクタリングを行うため、実装者側としては安心感がありました。テスト内容は一度記述したら変更しない以上、テストがパスしない箇所は実装部分に想定外の挙動をとっていると言えます。デバッグ容易性につながります。
3.疎結合を意識した実装
ユニットテストを実施する以上、他の関数とはできるだけ疎結合を保つ必要があります。依存性注入を行うことを意識した実装になりました。(普段もそうしていきたい
デメリット
1.実装に時間がかかる
2.テストコードに不具合があるとどうしようもない
3.ツールを色々入れる必要がある
1.実装に時間がかかる
完成後にテストを行う、受け入れテスト駆動開発と比較して開発期間が16%増すというデータがあります。シンプルな実装やユニットテストを完備しているという意味で、保守や維持コスト減を見据えた契約をとれるケースが好ましいと思いました。
2.テストコードに不具合があるとどうしようもない
誤ったテスト、誤った要件理解をしてしまうと、ずっと不具合無しという報告が出ます。特にユニットテストについては開発者がテスト作成してしまう上に1つ1つのテストを第三者がチェックできるのか、結合テストで検出するのか、組織の運用方針に一任されそうでした。
3.色々ツールを入れる必要がある
xUnit(x は任意の開発言語の略称)とモック・ダミー生成ツールは必須だと思いました。OSS が主ですが、開発が止まっているもの、色々なツールが出ているので選定と管理の方針についてすり合わせる必要がありそうです。
実装にあたって
1.関数単位に分割する
2.スモールステップで実装
3.DI で詳細の依存度を下げる
1.関数単位に分割する
自前で開発しているものについては、やはり書いては足してを繰り返してしまい、1 つの関数は積みあがったジェンガのようになってしまう。
関数は 1 つの機能に 1 つの役割を徹底させた。基本的にメインとなるメソッドは、返り値を受け取って代入させるだけの実装にして、細かな処理は関数に分けて分離させるように実装した。
2.スモールステップで実装
テストに失敗した後は、単体テストに通るための書き方を最初にするようにしている。これは原典通り。かっ飛ばして書いてしまうと、正しくない実装だったからテストに通らず、正しい実装をしたからテストに通ったと言いにくい。
このサイクルは非常にまどろっこしい反面、確実に前進はあるので結構好き。仕様書で結構決まっている場合は、判断を仰いで下さい。
3.DI で依存度を下げる
ここは賛否両論ありそう。関数同士の密結合を避けるために依存性注入(DI)できるような実装を心掛けた。テスト時は理想と同じ振舞いをするオブジェクトを用意することで、テスト環境準備の工数を下げることができる。
感想
とてもいい!福山でも掘り下げた感じの話がしたいです。
要件定義書がガチガチにある場合はそれを分解していく作業が入るので、工数はかさみます。PMと相談しましょう。