3

連続した呼び出しで異なる戻り値を許可するFakeItEasyを使用して偽物を作成するにはどうすればよいですか。これは私がやりたいことの一例です。

var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(true);  //Expected value for first call
A.CallTo(() => enumerator.Key).Returns("key1");
A.CallTo(() => enumerator.Value).Returns("value1");
A.CallTo(() => enumerator.MoveNext()).Returns(false); //Expected value for second call

Assert.IsTrue(enumerator.MoveNext());    //Fails
Assert.IsFalse(enumerator.MoveNext());   

MoveNextの最後の設定が最初の設定を上書きするため、アサーションは失敗します。

FakeItEasyでやりたいことをすることは可能ですか?

[編集]
元の質問の例を明確にし、以下の実用的な例を提供しました。

Patrikの回答に基づいて、このコードは偽物を設定する方法を示しています。秘訣は、すべての設定を逆にしてを使用することOnce()です。

var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(2);
A.CallTo(() => enumerator.Key).Returns("key2").Once();
A.CallTo(() => enumerator.Value).Returns("value2").Once();
A.CallTo(() => enumerator.Key).Returns("key1").Once();
A.CallTo(() => enumerator.Value).Returns("value1").Once();

while(enumerator.MoveNext())
{
    Debug.WriteLine(enumerator.Key + ": "+ enumerator.Value);               
}

これは印刷されます:

key1: value1
key2: value2
4

2 に答える 2

6

私はあなたが何を意味するのか完全にはわかりません、あなたが提供したコードは常に失敗します。ただし、 2回目に呼び出されたときにtrueを返したい場合は、それを実行できます。私が考えることができるいくつかの異なる方法があります、それらの2つは次のとおりです:

A.CallTo(() => enumerator.MoveNext()).ReturnsNextFromSequence(false, true);

他の方法は次のとおりです。

A.CallTo(() => enumerator.MoveNext()).Returns(true);
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();

編集:

第二に、私はあなたの質問をよりよく理解していると思いますが、あなたがしたいことは、MoveNextが最初はtrueを返し、2回目はfalseを返す必要があるということです。その場合は、上記の例の値の順序を変更するだけです。

FakeItEasyは記録/再生モデルを使用せず、最新の構成済みルールが以前に指定されたルールよりも優先されるという点で正しいです。そのため、最新の構成でrepeat( ".Once()")を指定して、1回だけ有効にする必要があります。

最新のものが優先される理由はたくさんありますが、最も重要な理由の1つは、フィクスチャのセットアップでデフォルトの戻り値を設定し、それをオーバーライドして一部のテストで特定の値を返すことができることです。これは、次の場合は不可能です。記録/再生モデルを使用します。

于 2011-03-02T20:54:55.137 に答える
0

Patrikの回答に基づくOPの例は問題ありませんが、シーケンスが大きくなると面倒です。その答えを補足するために、偽の/模擬の例は、ほとんどの場合、自分自身を配置するための一連の直線コードを示していますが、実際には、コマンドでプログラミング言語の全能力を持っていることを考慮してください。条件、ループ、さらにはプロシージャ。

したがって、次のことを考慮してください。

public static void AFakeDictionaryEnumeratorReturns(
                       IDictionaryEnumerator enumerator, params object[] pairs)
{
    if (0 != pairs.Length % 2)
        throw new ArgumentException("pairs must have even number of elements", "pairs");

    int n = pairs.Length / 2;

    A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
    A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(n);

    for (int i = pairs.Length; i > 0; i -= 2)
    {
        A.CallTo(() => enumerator.Key).Returns(pairs[i - 2]).Once();
        A.CallTo(() => enumerator.Value).Returns(pairs[i - 1]).Once();
    }
}

そして今、テストは次のようになります:

var enumerator = A.Fake<IDictionaryEnumerator>();
AFakeDictionaryEnumeratorReturns(enumerator, 
                                 "key1", "value1", "key2", "value2", "key3", "value3");

var keys = new List<object>();
var values = new List<object>();
while (enumerator.MoveNext())
{
    keys.Add(enumerator.Key);
    values.Add(enumerator.Value);
}

Assert.Equal(new List<object> { "key1", "key2", "key3" }, keys);
Assert.Equal(new List<object> { "value1", "value2", "value3" }, values);

IDictionaryEnumeratorペアでの取引であるため、この例は明らかに有益ではありません。標準IEnumerator<T>の場合、単一の静的ジェネリックメソッドが多数の異なる列挙子に役立ちます。)

于 2015-04-02T22:14:01.297 に答える