4

ファクトリ()を使用するクラスをテストしようとしていますが、Func<T>MoqとAutoFixtureを使用しています。

「環境」をセットアップして、ファクトリが使用されているかどうか、および返されたインスタンスで何回、どのメソッドが使用されているかを確認するための最良の方法は何ですか?

現在、私はモックを作成してTおりInjectingFunc<T>返されたすべてのモックインスタンスのカウントを保持しています。

public class SystemUnderTest {
    public SystemUnderTest(Func<IMyClass> c)
    {
        try {
            var c1 = c();
            c1.Name="n1";
            c1.Send();
        }
        catch(Exception){
            var c2 = c();
            c2.Name="n2";
            c2.Send();
        }
    }
}
private Mock<IMyClass> MockFactory()
{
   var m = new Mock<IMyClass>();
   m.SetupProperty(mc=>mc.Name);
   _returnedStubs.Add(m);
   return m;
}  
[Test]
public void TestSomething()
{
    var fixture = new Fixture();
    fixture.Inject(()=>MockFactory().Object)
    var sut = fixture.CreateAnonymous<SystemUnderTest>();
    Assert.That(_returnedStubs.Count,Is.Equal(1));
    _returnedStubs[0].Verify(m=>m.Send(),Times.Exactly(1));
    _returnedStubs[0].Verify(m=>m.Name = "n1");
}

しかし、それは私にはちょっと気難しい/醜い感じがします。そして、テストクラスのインスタンス変数は危険なものだと確信しています

4

2 に答える 2

7

AutoFixture は匿名デリゲートを作成できるため、 の匿名インスタンスを作成するように要求されるSystemUnderTestと、匿名デリゲートも自動的に提供され、呼び出されるFunc<IMyClass>と の匿名インスタンスが返されます。IMyClass

これは、このシナリオを考えると、次のことを意味します。

public class SystemUnderTest
{
    public SystemUnderTest(Func<IMyClass> c)
    {
        try
        {
            var c1 = c();
            // ...
        }
        catch (Exception)
        {
            var c2 = c();
            // ...
        }
    }
}

次のコード:

var fixture = new Fixture();
var sut = fixture.CreateAnonymous<SystemUnderTest>();

c1はとc2変数に の匿名インスタンスを割り当てますIMyClass。さらに、AutoFixture を自動モック コンテナーとして機能するように構成すると、たとえば を使用してAutoMoqCustomization、これらの匿名インスタンスIMyClassも Moq プロキシになります。

var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
var sut = fixture.CreateAnonymous<SystemUnderTest>();

ただし、この情報は有用ではありますが、特定のケースでは実際には役に立ちません。テストのファクトリ メソッドによって返されるモック オブジェクトを取得して、Func<IMyClass>それらの動作を構成し、それらがどのように動作するかについていくつかのアサーションを作成する必要があるためです。と交流しました。

私の意見では、最善の解決策は、ファクトリ メソッドの実装をからインターフェイスFunc<IMyClass>に変更することです。このようにして、メソッドがシーケンスで複数回呼び出されたときにインターフェイスのさまざまなモックを返す偽のファクトリを作成できます。IMyClassCreate

したがって、この例を考えると:

public interface IFactory<T>
{
    T Create();
}

public class SystemUnderTest
{
    public SystemUnderTest(IFactory<IMyClass> factory)
    {
        try
        {
            var c1 = factory.Create();
            // ...
        }
        catch (Exception)
        {
            var c2 = factory.Create();
            // ...
        }
    }
}

次のようにテスト シナリオをセットアップできます。

    // Given
    var c1 = new Mock<IMyClass>();
    var c2 = new Mock<IMyClass>();
    // TODO: setup the behavior of the mock objects
    var factory = new Mock<IFactory<IMyClass>>();
    factory.Setup(s => s.Create()).ReturnsInOrder(c1.Object, c2.Object);

    // When
    var fixture = new Fixture();
    fixture.Inject(() => factory.Object)
    var sut = fixture.CreateAnonymous<SystemUnderTest>();

    // Then
    // TODO: verify the expectations on the mock objects

これは、Moqのメソッドを使用して、連続して複数回呼び出されたときにスタブ化されたメソッドから異なる値を返すカスタム拡張メソッドReturnsInOrderであることに注意してください。Callback

于 2012-03-24T00:45:20.047 に答える
1

最善の方法の 1 つは、独自の関数を作成して渡し、そこに期待値または状態を設定することです。

int numberOfTimesUsed = 0;
myObject.Func = (x) => 
{ 
   numberOfTimesUsed++;
   Assert.IsNotNull(x); // checks if x passed was not null
};

...

Assert.AreEqual(2, numberOfTimesUsed); // checks if called twice
于 2012-03-23T12:59:19.040 に答える