internal を利用すれば、DI コンテナを使わなくても、呼び出すクラスをモックに差し替えられるんじゃないだろうか。
例えば次のクラス。
public class FooService { public Foo FindFoo(int id) { FooDataAccsss dac = new FooDataAccess(); return dac.Find(id); } public void CreateFoo(Foo data) { FooDataAccess dac = new FooDataAccess(); return dac.Create(data) } }
FooDataAccess のインスタンスを生成している箇所を、次のように書き変えてみる。
public class FooService { internal Func<FooDataAccess> CreateDataAccess; public FooService() { CreateDataAccess = () => new FooDataAccess(); } public Foo FindFoo(int id) { return CreateDataAccess().Find(id); } public void CreateFoo(Foo data) { CreateDataAccess().Create(data); } }
こうしておけば、テスト内で FooDataAccess の生成処理を差し替えることができる。テストプロジェクトのアセンブリを InternalVisibleTo に指定して、internal メンバへのアクセスを許可する必要があるけど。
FooService service = new FooService(); service.CreateDataAccess = () => { Mock<FooDataAccess> mock = new mock<FooDataAccess>(); mock.Setup(m => m.Find(10)).Returns(new Foo()); return mock.Object; };
ちなみに、上記の例では Moq を使っている。他のモックライブラリを使う場合は、インタフェースを用意するといった工夫が必要。
試してみた感想としては、単体テストはしやすくなるけど、美しくないなぁ。自分は CreateXXX みたいな、クラス内部だけで利用する生成メソッドをよく書くので、面倒だとは思わないけれど。