解決策が見つかったので、簡単に説明します。
AutoFixtureは、モックを正常にフリーズして返します。AutoFixtureによって生成された私のsutには、テストにとって重要なローカルデフォルトのパブリックプロパティがあり、AutoFixtureが新しい値に設定されていました。マークの答えからそれを超えて学ぶことがたくさんあります。
元の質問:
私は昨日、MoqがいたるところにあるxUnit.netテストでAutoFixtureを試し始めました。Moqのものの一部を置き換えたり、読みやすくしたりしたいと思っていました。特に、SUTFactoryの容量でAutoFixtureを使用することに興味があります。
AutoMockingに関するMarkSeemannのブログ投稿をいくつか用意して、そこから作業を試みましたが、それほど遠くはありませんでした。
AutoFixtureを使用しない場合のテストは次のようになります。
[Fact]
public void GetXml_ReturnsCorrectXElement()
{
// Arrange
string xmlString = @"
<mappings>
<mapping source='gcnm_loan_amount_min' target='gcnm_loan_amount_min_usd' />
<mapping source='gcnm_loan_amount_max' target='gcnm_loan_amount_max_usd' />
</mappings>";
string settingKey = "gcCreditApplicationUsdFieldMappings";
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
ITracingService tracing = new Mock<ITracingService>().Object;
XElement expectedXml = XElement.Parse(xmlString);
IMappingXml sut = new SettingMappingXml(settings, tracing);
// Act
XElement actualXml = sut.GetXml();
// Assert
Assert.True(XNode.DeepEquals(expectedXml, actualXml));
}
ここでの話は十分に単純です-正しいキー(ハードコードされている/プロパティが挿入されている)で依存関係をSettingMappingXml
クエリしISettings
、結果をとして返すことを確認してXElement
ください。エラーがあるITracingService
場合にのみ関連します。
私がやろうとしていたのは、ITracingService
オブジェクトを明示的に作成してから手動で依存関係を挿入する必要をなくすことです(このテストが複雑すぎるためではなく、試して理解するのに十分簡単だからです)。
AutoFixtureを入力してください-最初の試み:
[Fact]
public void GetXml_ReturnsCorrectXElement()
{
// Arrange
IFixture fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
string xmlString = @"
<mappings>
<mapping source='gcnm_loan_amount_min' target='gcnm_loan_amount_min_usd' />
<mapping source='gcnm_loan_amount_max' target='gcnm_loan_amount_max_usd' />
</mappings>";
string settingKey = "gcCreditApplicationUsdFieldMappings";
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
fixture.Inject(settings);
XElement expectedXml = XElement.Parse(xmlString);
IMappingXml sut = fixture.CreateAnonymous<SettingMappingXml>();
// Act
XElement actualXml = sut.GetXml();
// Assert
Assert.True(XNode.DeepEquals(expectedXml, actualXml));
}
CreateAnonymous<SettingMappingXml>()
コンストラクターパラメーターが検出されると、そのインターフェイスに具体的なインスタンスが登録されていることに気づき、それを注入することを期待ISettings
しますが、それは行わず、代わりに新しい匿名の実装を作成します。
fixture.CreateAnonymous<ISettings>()
実際に私のインスタンスを返すので、これは特に混乱します-
IMappingXml sut = new SettingMappingXml(fixture.CreateAnonymous<ISettings>(), fixture.CreateAnonymous<ITracingService>());
テストを完全にグリーンにします。この行は、インスタンス化するときにAutoFixtureが内部で実行することを期待していたものとまったく同じSettingMappingXml
です。
次に、コンポーネントをフリーズするという概念があるので、モックオブジェクトを取得するのではなく、フィクスチャ内のモックをフリーズするだけで済みます。
fixture.Freeze<Mock<ISettings>>(f => f.Do(m => m.Setup(s => s.Get(settingKey)).Returns(xmlString)));
確かに、これは完全に正常に機能します-SettingMappingXml
コンストラクターを明示的に呼び出し、に依存しない限りCreateAnonymous()
。
簡単に言えば、それが私が思いつくことができるどんな論理にも反するので、なぜそれが明らかにそれがするように働くのか理解していません。通常、私はライブラリのバグを疑うでしょうが、これは非常に基本的なものであるため、他の人がこれに遭遇し、長い間発見されて修正されていたと確信しています。さらに、テストとDIに対するMarkの熱心なアプローチを知っているので、これは意図的ではありません。
つまり、私はかなり初歩的な何かを見逃しているに違いありません。事前設定されたモックオブジェクトを依存関係としてAutoFixtureでSUTを作成するにはどうすればよいですか?私が今確信している唯一のことは、私が必要としているので、のAutoMoqCustomization
ために何も設定する必要がないということですITracingService
。
AutoFixture / AutoMoqパッケージは2.14.1、Moqは3.1.416.3で、すべてNuGetからのものです。.NETバージョンは4.5(VS2012とともにインストール)であり、動作はVS2012と2010で同じです。
この投稿を書いているときに、Moq 4.0とアセンブリバインディングリダイレクトに問題があることがわかったので、Moq 4のすべてのインスタンスのソリューションを細心の注意を払ってパージし、AutoFixture.AutoMoqを「クリーンな」プロジェクトにインストールしてMoq3.1をインストールしました。ただし、私のテストの動作は変更されていません。
ポインタや説明をありがとうございます。
更新: Markが要求したコンストラクターコードは次のとおりです。
public SettingMappingXml(ISettings settingSource, ITracingService tracing)
{
this._settingSource = settingSource;
this._tracing = tracing;
this.SettingKey = "gcCreditApplicationUsdFieldMappings";
}
完全を期すために、GetXml()
メソッドは次のようになります。
public XElement GetXml()
{
int errorCode = 10600;
try
{
string mappingSetting = this._settingSource.Get(this.SettingKey);
errorCode++;
XElement mappingXml = XElement.Parse(mappingSetting);
errorCode++;
return mappingXml;
}
catch (Exception e)
{
this._tracing.Trace(errorCode, e.Message);
throw;
}
}
SettingKey
単なる自動プロパティです。