応用2: 現在時刻プロパティのインターフェースを定義して使い分ける
本来の実装と、テスト用実装を切り分けるために、インターフェースを導入します。
public interface ISystemClock { DateTimeOffset 現在時刻 { get; } }
現在時刻プロパティの部分を、このインターフェースを実装するように変更します。
[TestCase] public void InterfaceTest() { var clock = new SystemClock(); Assert.IsInstanceOf<ISystemClock>(clock); }
public class SystemClock : ISystemClock { public DateTimeOffset 現在時刻 { get { return DateTimeOffset.Now; } } }
現在時刻をフォーマットするメソッドは、ISystemClock
インターフェースのオブジェクトを利用するようにします。その方法としては、UnityなどのDIコンテナーを使うこともできますが、ここでは簡単のためにメソッドの引数として渡すことにします。
public static string Getフォーマット済み現在時刻(ISystemClock systemClock) { return systemClock.現在時刻.ToString("hh時 mm分 ss秒"); }
応用2-1: SystemClockのダミーを自作する
ISystemClock
インターフェースの実装は、可能ならば自前でダミーを作ってしまうと確実です。ここでも省略しますが、ダミーのためのユニットテストを書いてから、それを通すように次のようにテストプロジェクト側に実装を作ります。
public class SystemClockDummy : ISystemClock { internal DateTimeOffset テスト用_現在時刻 { get; set; } public DateTimeOffset 現在時刻 { get { return テスト用_現在時刻; } } }
このダミークラスを使って、ユニットテストを記述します。
[TestCase] public void Getフォーマット済み現在時刻Test_自作ダミーを使う() { var givenTime = new DateTimeOffset(new DateTime(2012, 8, 8, 14, 3, 0)); var clock = new SystemClockDummy(){ テスト用_現在時刻 = givenTime, }; Assert.AreEqual("14時 03分 00秒", Class3.Getフォーマット済み現在時刻(clock)); }
応用2-2: SystemClockのモックを使う
ダミーを作るのが難しい場合には、モックオブジェクトを使います。モックは、そのテストに必要な挙動だけを定義すればよいので、複雑なダミーを作るよりはシンプルに書くことができます。その反面、挙動が変更になった時には、関連するすべてのテストでモック生成部分の修正が必要になります。
ここでは、NUnit付属のNSubstituteを使ってみましょう。NUnit 2.6をインストールした場合には、システムドライブの\Program Files (x86)\NUnit 2.6\bin\libフォルダーにNSubstitute.dllが入っているので、テストプロジェクトの参照設定に追加します。テストコードには、using NSubstitute;
を追加します。すると、次のようにテストコードが書けます。
[TestCase] public void Getフォーマット済み現在時刻Test_モックを使う() { var givenTime = new DateTimeOffset(new DateTime(2012, 8, 8, 14, 3, 0)); var clock = Substitute.For<ISystemClock>(); //モックオブジェクトを生成 clock.現在時刻.Returns(givenTime); //テストに必要な挙動だけを定義 Assert.AreEqual("14時 03分 00秒", Class3.Getフォーマット済み現在時刻(clock)); }
まとめ
- 制御しにくいものは切り離せ! 手動でテストしなければならないコードを、できるだけ少なくしよう。
- 制御しにくい部分に、#if ディレクティブを使ってテスト用の実装を埋め込む方法。簡便だが、製品コードが汚くなる。
- 制御しにくい部分のダミーを自作する方法。複雑な場合は、作るのがたいへん。制御しにくい部分の仕様が変わった時には、ダミーを修正すれば済む。
- 制御しにくい部分をモックで代用する方法。テストを書くときは、とても楽。制御しにくい部分の仕様が変わった時には、テストコードの修正箇所が多くなるので、修正漏れに注意。
- 緊急避難的に、Visual Studio 2012の上位版に正式搭載されるFakesのシムを使うことも。テスト時間が長くなるし、テスタビリティに欠ける設計をしているということであるから、TDDでは避ける。後付けでテストを作る際には有用。