2012-03-13 87 views
2

我一直試圖解決這個問題幾天,現在無濟於事。我試圖測試AnObject.AnAction的功能(搶先道歉,我不得不混淆類/方法名稱)。我的目標是讓MyTestObj.do_work(AnObject)在調用它時實際做任何事情。它有我想在單元測試環境中調用的代碼。Moq錯誤:無法將'AnObject'強制轉換爲'System.Delegate'

這裏是我的單元測試代碼:

Mock<MyTestObj> myTestObj_mock = new Mock<MyTestObj>(); 
myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>())); 
... 
AnObject tester = new AnObject(); 
tester.anAction(myTestObj_mock.Object); 

方法AnObject.AnAction(MyTestObj MTO)內:

... 
mto.do_work(this); 
... 

正是在這一點上跑的時候,我得到這個錯誤:

System.InvalidCastException : Unable to cast object of type 
'myNamespace.AnObject' to type 'System.Delegate'.  

MyTestObj.do_work是一個虛擬方法。

我完全不知道爲什麼會出現這個錯誤。當NUnit運行它時,我已經完成了代碼,我確定這是它崩潰的地方。它不會再進入代碼。

我真的很難過。有人知道發生了什麼嗎?

在此先感謝!


***更新* **

我試圖內AnObject.AnAction創建AnObject的實例,並通過它,而不是 '本':

... 
AnObject test = new AnObject(); 
mto.do_work(test); 
... 

這沒有任何效果。

+0

什麼do_work(param?)中的參數? – 2012-03-13 20:32:17

+0

AnObject的一個實例。 – CodeSlinger512 2012-03-13 20:34:12

+0

出於好奇,你是否嘗試過傳入其他東西(新建一個AnObject)並運行測試? – 2012-03-13 20:41:42

回答

3

隨着你的問題被編寫,你不需要設置myTestObj_mock.do_work()。

安裝程序用於說方法X被稱爲返回值Y.或者,當方法X被調用時,返回異常Z.問問你自己,那真的是我需要做的?此外

mto.do_work(this); 

,在這裏:

在這裏你是不是從方法返回任何東西

myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>())); 

您沒有定義您的設置任何回報。

在這種情況下,您應該能夠提供模擬myTestObj_mock,而無需定義設置。只需使用安裝程序刪除該行並再次運行測試。

猜測:

如果你定義的設置,因爲你想你的測試,以確保AnObject。AnAction真正調用do_work方法,你需要做的是定義一個驗證方法,而不是設置,同樣:

mock.Verify(foo => foo.Execute("ping")); 

或在您的情況類似

myTestObj_mock.Verify(m => m.do_work(It.IsAny<AnObject>()), Times.AtLeastOnce()); 

另一種猜測:

如果你定義了模擬是因爲你傳遞了一個「this」引用,並期望do_work修改了「this」的某些參數供測試通過,那麼你不應該在這裏嘲笑。請記住,mock並不是您的對象的實例,因此修改此引用的代碼將永遠不會被調用。

+0

我給你的建議沒有任何運氣一槍。 此外,我不測試MyTestObj類,但AnObject類。 MyTestObj.do_work(AnObject)調用某些不適用於單元測試的聯網過程。我正在調用Setup方法,以便虛擬出方法,所以它什麼都不做。 對不起,我真的應該說得更清楚。 – CodeSlinger512 2012-03-14 14:27:21

3

我終於能夠進入編譯器並使用代碼進行遊戲,這就是我發現的。這基本上是蓋爾斯在第一部分的問題中所說的。

下面是安裝代碼提示:

Specifies a setup on the mocked type for a call to a value returning method.

而且,這裏是設置

public ISetup<T> Setup(Expression<Action<T>> expression) 

所以實際的代碼,設置實際上是建立代碼作爲一個Action(委託,基本上)。當運行測試運行,它擊中了這一點,通常希望委託喂到迴歸方法

public IReturnsResult<TMock> Returns(TResult value) 

所以,這是從來沒有完成,而不是模擬貫穿整個預期路徑和談判所有的代碼出來,然後返回錯誤輸入的值。

Sooo,這基本上就是Giles解釋正確的地方。如果你正在測試do_work方法被調用,那麼你想使用Verify(它真正使用你的假對象作爲模擬)。但是,如果沒有,那麼你甚至不需要設置它,因爲它什麼也不做。如果是這樣的話,那麼也許這段代碼不應該在特定的代碼塊中,但你最好評估一下。

最後,只有在您真正將您的對象用作存根時才使用安裝方法,只需使用它將代碼注入邏輯即可。

希望這是有道理的,並幫助您解決您的問題。

此外,Callback可能在這裏使用,這取決於你在做什麼。但是,我不確定。他們在Moq quickstart

更新My企圖在使用版本4.0.10827重現許多例子...並沒有遇到任何問題

[Test] 
    public void teststuff() 
    { 
     Mock<MyTestObj> myTestObj_mock = new Mock<MyTestObj>(); 
     myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>())); 
     AnObject tester = new AnObject(); 
     tester.anAction(myTestObj_mock.Object); 
    } 

...

public class MyTestObj 
{ 
    public virtual void do_work(AnObject o) 
    { 

    } 
} 

public class AnObject 
{ 
    public void anAction(MyTestObj obj) 
    { 
     obj.do_work(new AnObject()); 
    } 
} 
+0

另外,最重要的是,它確實看起來像這種已經被問過...排序http://stackoverflow.com/questions/1203529/short-circuiting-void-methods-with-moq – 2012-03-14 15:06:52

+0

你的一切「說的話是有道理的。就像你分享的鏈接一樣,我希望do_work不要做任何事情。我真的不在乎確定它是否被調用。我刪除了安裝程序代碼行,並試圖讓它按原樣運行,但它仍然反彈了相同的錯誤。 – CodeSlinger512 2012-03-14 15:21:00

+0

如何確保我們在正確的路徑上,添加.Verifiable();到設置並看看它是否工作。您不必打電話驗證我相信。如果這不起作用,(甚至如此),那麼我會好奇,看看是否設置一個沒有任何回調的回調可能在這裏工作。 .Callback(()=> {}); – 2012-03-14 15:28:40

相關問題