既存システムでTDDするのが難しい理由

TDDしたい、CIしたいと思ってもなかなか導入できない。何でだろう?
PHP製WebアプリケーションでのTDDを学び始めた現時点の気持ちまとめ。

Seleniumを使うような高いレイヤーのテスト

どんなテストを書けばいいのかわからない

例えばDBから商品情報取ってページ生成する場合。

  • 商品カテゴリごとに異なる趣きのページを作るのでそれぞれにviewのテストを書いたとする
  • 各ページ内の商品詳細URLにパラメータが追加されることになった
  • URL生成は共通のモデルで行っている
  • 修正は一ヶ所で簡単なもの

だったとしてもviewのテストはそうは行かない。
先に用意したテストケースを全部書き直さなきゃならない。

小さな変更にかかるコストが大きくなる

単純に時間がかかるというより
めんどくさくなる → どうせやらなくなる

という思い。

コントローラーとか中間くらいの層のテスト

viewよりは下、ユニットよりは上、複数モデルを組み合わせて使うような部分とか。

リファクタリングしないとテストできない

テスト用DBとかモックとか使う必要がある点で敷居が高いのと、そもそもモックが使える様にする為に、派手にリファクタリングして依存性を外から注入できるようにしないといけない。

勝手にリファクタリングできない

今のコードベースばテストはしづらいものの、統一された規約や作法、設計思想に基づいて作られているので一部だけ勝手にリファクタリングなんて出来ない。アーキテクトの意思決定が必要。 実践した経験も無くその効果も良くわからないのに提案もくそもない。

一からやり直したくなる病

というか、そこまでがっつり変更するなら初めからこれらのテストが機能として組み込まれたフレームワークに乗り換えて心機一転の機会を私待ーつーわ。

という思い。

モデル内のメソッドに対するユニットテスト

やっぱりテストできない

1ドメイン1モデルクラスみたいな感じでメソッドがまとまってて結構な数のprivateメソッドがあったりする。
PHP5.3だったらリフレクションでprivateメソッドも実行できるが、うち5.2だし!
オブジェクト指向的には1クラス1責務なんだろうけど、これに従って大量にクラス分割する様なリファクタリングするには相当な覚悟がいるよね・・・
というかそもそも1ドメイン1クラス設計もありなんじゃないか。

という思い。

まず手をつけるなら最も低いレイヤーのユニットテスト

はじめの一歩はここが本命じゃなかろうか

とりあえず手がかりをつかむために、モデルクラスの中のごく一部のメソッドからでも。privateなのを試しにpublicにしちゃうとか、クラス分割できるならちょっと一瞬やってみちゃうとか、もしくはユーティリティ的にstaticに定義されてる関数とか、そのへんを狙えばテストを書いていけそう。

保護するためのテストという考えを捨てる

気持ちを切り替えて敷居を下げる。
あれもこれもassertしなきゃ、こんな中途半端なテストじゃ足枷にしかならないんじゃ、と考えるのをやめる。設計を整理して仕様を明確にするために最低限のテストを書くと考える。

  • コメントで「//このフラグは○○なので注意」みたいなことを書きたくなったらそれをテストに書こう
  • デバッグでprint_rとかしたくなったらそれをテストに書こう

こんな感じ。