たられ話

人生に「たら」「れば」無し

TDDにおける接合部の基準

最近はもっぱら、テストファーストでコーディングすることを意識するようになりました。

そのときに問題となるのが、
他のクラスやデータに依存しすぎてメソッドをそのまま呼ぶことができない、
あるいは、そのメソッドを呼ぶのに必要な準備が多すぎて
テストコード自体が複雑になってしまったりということが多々あります。

こういう状況に陥るということは、設計が不十分だからに他ならないのですが、
じゃあどうやって上の状況を避けるかと言えば、
メソッドを複雑にしてしまっている原因を分離する必要があります。

これについて、「レガシーコード改善ガイド」という本では、
接合部という言葉を使って、解決策を示しています。

接合部というのは、ポリモーフィズムによってあるメソッドの振る舞いを
テストの時と本番の時で変えることのできるポイントのことです。

たとえば、以下のdoSomething()メソッドをテストしたいときに

class Something
{
    public void doSomething()
    {
        ...
        job.work();
        ...
    }
}

class Job
{
    public void work()
    {
        // ものすごく時間がかかる処理
        ...
    }
}

そのままテストをすると、job.work()が邪魔して、
テストをするのに支障があるときに、何か別のものに置き換えてしまえば
その影響を排除できると言うことです。
(ただし、内部でグローバル変数を使ってるとか戻り値が必要だとかっていう
副作用がある場合はまた別にそれも考慮に入れなければなりません。)

interface Job
{
    public abstract void work();
}

class HeavyJob implements Job
{
    @Override
    public void work()
    {
        // 重い処理
        ...
    }
}

class MockJob implements Job
{
    @Override
    public void work()
    {
        // 何もしない
    }
}

単体テストでは、そのメソッドの責任のみを確かめるのが目的なので、
このように、邪魔な部分を一時的に上書きするのはとても都合がいいです。

個人的に、接合部に適してるな~って思う部分をまとめると、

  • その言語のシンタックスシュガー
  • 重い処理
  • 外部のアプリケーションやハードが必要になる部分(データベース、ソケットなど)
  • ライブラリ
  • OSによって挙動が変わる部分(システムコールとか)
  • スレッド、GUI
  • 毎回値が変わる部分(乱数、現在時刻など)
  • グローバル変数(シングルトンも含む)

現時点ではこんなところでしょうか。
試行錯誤の段階なので、今後いろいろと変わるかもしれないですが。