2016-02-11 194 views
1

我寫了下面的示例中LINQPad 4(v.4.57.02)證明試圖用NSubstitute(v1.9.2.0)嘲笑類型的愚蠢和它的非虛擬財產:奇怪的行爲與NSubstitute

void Main() 
{ 
    var foo = Substitute.For<Foo>(); 
    foo.Alarm.Returns(2);  
    foo.Alarm.Dump(); 
} 

public class Foo 
{ 
    public Foo() 
    { 
     Console.WriteLine("Foo ctor called."); 
    } 

    public virtual int Alarm 
    { 
     get; set; 
    } 
} 

此代碼工作正常,並給出了以下的輸出:

Foo ctor called. 
2 

現在,當我編輯的代碼,以消除對Alarm財產virtual修改,我期待着看到一個NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException包括智慧在內的例外情況:

如果您替換了某個類而不是某個接口,請檢查對替代者的調用是否在虛擬/抽象成員上。無法爲非虛擬/非抽象成員配置返回值。

然而,第一一次運行修改後的代碼我得到:

Foo ctor called. 
0 

而且在隨後的運行中,我得到了預期的異常。

現在我懷疑LINQPad管理AppDomain的方式以及NSubstitute的城堡代理如何工作 - 但我不知道是什麼。舉起手來,我只是沒有時間深入研究,並想知道是否有其他人有明確的解釋,因爲知道LINQPad執行環境中的陷阱會令人欣慰。

回答

2

如果您開始打開一個LINQPad的新實例並運行代碼而不使用virtual成員,它將立即失敗並出現預期錯誤。

所以這裏是我猜測發生了什麼。第一次代碼與virtual成員NSubstitute的狀態下運行是這樣的:以替代靜態的最後一次通話

var foo = Substitute.For<Foo>(); 
foo.Alarm   // 1. last call is foo.Alarm 
    .Returns(2); // 2. make foo.Alarm return `2`. Clear last call. 
foo.Alarm   // 3. last call is foo.Alarm 
    .Dump();  // 4. extension method -- doesn't clear last call 

NSubstitute店,所以直到AppDomain中消失它徘徊。當您修改代碼以刪除virtual並再次運行時,步驟2中的.Returns(2)將查找上一次運行的第3步中進行的最後一次呼叫,並相應地對其進行存根,然後清除最後一次呼叫。由於非虛擬成員,未記錄其他呼叫,因此後續運行失敗並出現預期錯誤。

+0

這當然有很大的意義。好一個。 –

+1

此外,重要的是要注意來自上一次運行的調用是在存根對象的另一個實例上,這意味着'.Returns(2)'調用是在不再可從LINQPad代碼訪問的對象上進行的,但是可以訪問來自NSubstitute中「最後呼叫」概念的靜態存儲。 –