現実問題最初からTDDで書かれたプロダクトにはあまりお目にかかれない。
TDDはコードの設計とユニットテストの自動化を、実装を書く前に同時に行えるので、とても効率的で且つある程度高い水準の実装を行うことができます。しかしながらそれが上手くいくのは、まだプロダクトが真っ新か、全部TDDで作成されたときに限り、そうでない場合は依存性が高くてモック化が難しかったりで簡単にはできません。
そして大抵の場合は、TDDで全部開発されたプロダクトに遭遇するのは稀です…
理論通りの完璧なTDDを行うのは難しいので、それに限りなく近いやり方でTDDの恩恵を受けるほかありません。
参加しているプロダクトの状態を知る
このサイトではTDDの状態は4つの境界に分かれると説明されていました。
- TDDニンジャ
- 完璧なTDD。必ずテストの作成を行ってから実装を行う。完璧なTDDで作られたプロダクトと、チームメンバ全員が高いレベルのTDDに関する知識があって初めて成立する。
- 実用的TDD
- クラス・メソッドシグネチャの定義をしてからテストを書き、実装を行う。APIの開発ではSwaggerなどの部分をテストよりも先に設計する。比較的一番実用的にTDDを導入できる。
- レガシー向けTDD
- 古いコードでTDDを導入する際に、既存の機能の拡張や変更の際に、TDDしやすいように実装部を修正してからテストコードを書き始める。
- TDDっぽい何か
- 当人たちはTDDだと思っている何か。テストを書きながら実装を行うので、テストと実装が同じタイミングでコミットされる。
可能であるなら1番の状態にしたいですが、そんなにうまくいかないので2番の状態にまで持ち込むのが理想的です。
上手にTDDを導入するには?
上記で引用したサイトでは、TDDをうまく導入するヒントが載っていました。結構一般的な課題であるようなので、探せばいくつか導入のコツとなる方法が見つかります。
まとめ:テストは簡単。モック化は困難。
TDDを実践してわかったことは、(まだ経験が浅いのもありますが)出力の検証とかテスト対象の動作の再現とかは比較的簡単にできるのに、ユニットが依存している物の参照とモック化はTDD向けに書かれた実装でない限りは難しくなりやすいということです。(比較的楽にモック化できるものもある)TDDをプロダクトに導入する際は、テストし易くするために少しずつ修正する必要があります。それに加えてせっかくTDDを導入するのですから、テストの導入で難しかった個所を記録しておいて、自分たちがこれから新しく実装するものに関してはクラスの依存性を抑えてモック化しやすいようにDI(依存性注入)などのパターンを活用したりして少しずつ高いレベルのTDD開発に近づけていく事が大切かなと思いました。