そのテストは、1) 読みやすく、2) 書きやすく、保守しやすいものでなければなりません。「読める」とは?これは、特定のコード行で何が行われているかを理解するためにコードをジャンプする量を最小限に抑えることを意味します。
テスト プロジェクトでファクトリを作成することを検討してください。これは、テストの配置を読みやすくするための最良の方法の 1 つだと思います。
public static class MyClassFactory
{
public static MyClass Create(ISomeService serviceA, ISomeOtherService serviceB)
{
return new MyClass(serviceA, serviceB);
}
public static MyClass CreateEmpty()
{
return new MyClass();
}
//Just an example, but in general not really recommended.
//May be acceptable for simple projects, but for large ones
//remembering what does "Default" mean is an unnecessary burden
//and it somehow reduces readability.
public static MyClass CreateWithDefaultServices()
{
return new MyClass(/*...*/);
}
//...
}
(2 番目のオプションについては後で説明します)。次に、次のように使用できます。
[TestMethod]
public void it_should_do_something()
{
//Arrange
var myClass = MyClassFactory.Create(serviceA, serviceB);
//Act
myClass.DoSomething();
//Assert
//...
}
読みやすさが向上することに注意してください。あなたの例に合わせるためだけに残したserviceA
とserviceB
のほかに、理解する必要があるすべてがこの行にあります。理想的には、次のようになります。
[TestMethod]
public void it_should_do_something()
{
//Arrange
var myClass = MyClassFactory.Create(
MyServiceFactory.CreateStubWithTemperature(45),
MyOtherServiceFactory.CreateStubWithContents("test string"));
//Act
myClass.DoSomething();
//Assert
//...
}
これにより可読性が向上します。DRYが使用されていないセットアップであっても、すべてのファクトリ メソッドは単純で明白です。それらの定義を調べる必要はありません。一目で明らかです。
書きやすさと保守のしやすさをさらに向上させることはできますか?
MyClass
クールなアイデアは、読み取り可能な構成を可能にするために、テスト プロジェクトに拡張メソッドを提供することです。
public static MyClassTestExtensions
{
public static MyClass WithService(
this MyClass @this,
ISomeService service)
{
@this.SomeService = service; //or something like this
return @this;
}
public static MyClass WithOtherService(
this MyClass @this,
ISomeOtherService service)
{
@this.SomeOtherService = service; //or something like this
return @this;
}
}
次に、もちろん、次のように使用します。
[TestMethod]
public void it_should_do_something()
{
//Arrange
var serviceA = MyServiceFactory.CreateStubWithTemperature(45);
var serviceB = MyOtherServiceFactory.CreateStubWithContents("test string");
var myClass = MyClassFactory
.CreateEmpty()
.WithService(serviceA)
.WithOtherService(serviceB);
//Act
myClass.DoSomething();
//Assert
//...
}
もちろん、サービスはそのような構成の良い例ではありません (通常、サービスはそれらなしでは使用できないため、デフォルトのコンストラクターは提供されていません) が、他のプロパティには大きな利点があります: 構成する N 個のプロパティを使用すると、クリーンで読み取り可能なN x N ファクトリ メソッドの代わりに N 個の拡張メソッドを使用し、コンストラクタまたはファクトリ メソッドの呼び出しで N の長さの引数リストを使用せずに、可能なすべての構成でテスト オブジェクトを作成する方法。
クラスが上で想定したほど便利でない場合、考えられる解決策の 1 つはクラスをサブクラス化し、サブクラスのファクトリと拡張機能を定義することです。
オブジェクトがそのプロパティの一部だけで存在することが意味がなく、それらを設定できない場合は、ファクトリを流暢に構成してからオブジェクトを作成できます。
//serviceA and serviceB creation
var myClass = MyClassFactory
.WithServiceA(serviceA)
.WithServiceB(serviceB)
.CreateMyClass();
そのようなファクトリのコードが推測しやすいことを願っているので、この回答はすでに少し長いように思われるため、ここには書きません ;)