このようなファクトリ( xUnit.netを使用)のいくつかの単体テストの1つを作成する方法は次のとおりです。
[Fact]
public void CreateReturnsInstanceWithCorrectParam1()
{
var sut = new FooFactory();
var expected = new object();
var actual = sut.Create(expected, new object());
var concrete = Assert.IsAssignableFrom<Foo>(actual);
Assert.Equal(expected, concrete.Object1);
}
カプセル化を破りますか?はい、いいえ...少し。カプセル化とは、データを隠すことだけではありません。さらに重要なことは、オブジェクトの不変条件を保護することです。
FooがこのパブリックAPIを公開していると仮定しましょう:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
プロパティはデメテルObject1
の法則にわずかに違反していますが、読み取り専用であるため、クラスの不変条件を混乱させることはありません。
さらに、Object1
プロパティは具体的なFooクラスの一部であり、IFooインターフェイスではありません。
public interface IFoo
{
void MethodDefinedByInterface();
}
緩く結合されたAPIでは、具象メンバーが実装の詳細であることに気付くと、そのような具象のみの読み取り専用プロパティがカプセル化に与える影響は非常に小さくなります。このように考えてください:
パブリックFooコンストラクターも具象FooクラスのAPIの一部であるため、パブリックAPIを調べるだけで、それを学習しparam1
、param2
クラスの一部になります。ある意味で、これはすでに「カプセル化を破る」ので、各パラメーターを具象クラスの読み取り専用プロパティとして使用可能にすることはあまり変わりません。
このようなプロパティは、工場から返されるFooクラスの構造形状を単体テストできるという利点を提供します。
これは、具体的なFooクラスをすでにカバーしていると想定しなければならない一連の動作ユニットテストを繰り返すよりもはるかに簡単です。これは、ほとんど論理的な証明のようなものです。
- 具体的なFooクラスのテストから、コンストラクターパラメーターを正しく使用/相互作用することがわかります。
- これらのテストから、コンストラクターパラメーターが読み取り専用プロパティとして公開されていることもわかります。
- FooFactoryのテストから、具象Fooクラスのインスタンスが返されることがわかります。
- さらに、Createメソッドのテストから、そのパラメーターがFooコンストラクターに正しく渡されることがわかります。
- QED