2011-03-02 51 views
3

如何在連續調用中允許不同的返回值的FakeItEasy創建一個僞造品。這是我想什麼,能夠做一個例子:因爲它在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 

回答

6

我不能完全肯定,我明白你的意思,你提供的代碼總是會失敗。但是,如果你的意思是你想讓它返回真的時間,那麼它可以完成。有幾個不同的方式,我能想到的,他們兩個是:

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

另一種方法是:

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

編輯:

在第二,雖然我猜我更好地理解您的問題,您希望發生的事情是MoveNext應該第一次返回true,第二次返回false?如果是這種情況,只需在上面的示例中更改值的順序即可。

FakeItEasy不使用記錄/重播模型,並且您正確的是最新配置的規則優先於任何先前指定的規則。這就是爲什麼你必須指定重複 - 「.Once()」 - 在最新的配置,它只有一次有效。

爲什麼最新優先有很多原因,其中最重要的原因之一是它允許您在夾具設置中設置默認返回值並覆蓋它以返回某些測試中的特定值,這在使用記錄/重放模型時是不可能的。

+0

是的,你是對的。我在錄製/重放模型之後。有意義FakeItEasy沒有一個。我將編輯我的問題,幷包含一個可以使用兩個MoveNext值的工作示例。謝謝您的幫助。 – hcanber

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>,單個靜態泛型方法可用於大量不同的枚舉器。)