2008-11-26 272 views
2

作爲RhinoMocks和單元測試的新手,我遇到了一個問題,我似乎無法找到解決方案(無論我讀了多少文檔)。RhinoMocks事件訂閱

問題是這樣的:我創建了一個接口,公開了5個事件(用於ASP.NET中的視圖和MVP監督控制器模式.....我知道,我應該使用MVC,但是這是另一個問題)。無論如何,我想測試一下,當某個事件在視圖上觸發時,我們將其稱爲「IsLoaded」,調用Presenter中的方法,並使用Dependency Injection從Dependency返回一個值並將其設置爲風景。這裏是問題開始的地方:當我使用Expect.Call(Dependency.GetInfo())。Return(SomeList)時,調用永遠不會執行(不調用mock.ReplayAll()方法)。那麼,當我調用ReplayAll方法時,由於Presenter對象對由View接口公開的其他事件的預訂,我得到ExpectationExceptions。因此,對於我來測試,IView.IsLoaded已經解僱了,我想驗證IView.ListOfSomething已經更新,以匹配我通過Expect.Call()傳入的列表。但是,當我設置期望時,其他事件訂閱(直接從Presenter的構造函數中出現)無法通過測試的#0期望。我得到的是,view.Save + = this.SaveNewList拋出一個RhinoMocks ExpectationViolationException。

我的百萬美元的問題是這樣的嗎?是否有必要爲所有事件設置期望值(通過[Setup]),還是有什麼我缺少/不瞭解Unit Testing或RhinoMocks的工作原理?

請記住我是極其新單元測試,因此RhinoMocks。如果看起來我不知道我在說什麼,請隨時指出。

+0

只是一個更新,因爲它可能會幫助其他人有這個相同的問題:我發現了我的致命缺陷。以我的新手方式,我沒有使用mock.DynamicMock <>創建視圖模擬,而是使用.CreateMock <>創建。傻我。那些「非定義的」方法調用導致了異常。 – jstephenson 2008-11-26 20:43:27

回答

2

我正在開發一個項目,我們也使用MVP和rhino mocks。我們所做的只是期望在每個測試中的所有事件訂閱。

private void SetupDefaultExpectations() 
    { 
     _mockView.Initializing += null; LastCall.IgnoreArguments(); 
     _mockView.SavingChanges += null; LastCall.IgnoreArguments(); 
    } 

然後我們建立在IMockedObject(從RhinoMocks)一個擴展方法來觸發單元測試和未包裝的異常事件,以便他們可以在標準NUnit的方式可以預期的。

static class IMockedObjectExtension 
{ 
    public static void RaiseEvent(this IMockedObject mockView, string eventName, EventArgs args) 
    { 
     EventRaiser eventraiser = new EventRaiser(mockView, eventName); 

     try 
     { 
      eventraiser.Raise(mockView, args); 
     } 
     catch (TargetInvocationException ex) 
     { 
      throw ex.InnerException; 
     } 
    } 

    public static void RaiseEvent(this IMockedObject mockView, string eventName) 
    { 
     RaiseEvent(mockView, eventName, EventArgs.Empty); 
    } 
} 

這然後可以從該單元測試像這樣使用

using(_mocks.Record()) 
{ 
    Expect.Call(dependency.GetInfo()).Return(someList); 
} 
using(_mocks.Playback()) 
{ 
    Presenter presenter = new Presenter(_mockView, dependency); 
    (_mockView as IMockedObject).RaiseEvent("SavingChanges"); 
} 

爲了消除演示測試之間的重複我們已重構這個到BasePresenterTest基類,它設置了該基本結構爲所有演示測試並將輔助方法公開給子類。

public abstract class BasePresenterTest<VIEW> where VIEW : IBaseView 
{ 
    protected MockRepository _mocks; 
    protected VIEW View { get; private set; } 

    protected abstract void SetUp(); 
    protected abstract void TearDown(); 
    protected abstract void SetupDefaultExpectations(); 

    [SetUp] 
    public virtual void BaseSetUp() 
    { 
     _mocks = new MockRepository(); 
     View = _mocks.CreateMock<VIEW>(); 

     SetUp(); 
    } 

    [TearDown] 
    public virtual void BaseTearDown() 
    { 
     TearDown(); 

     View = null; 
     _mocks = null; 
    } 

    protected virtual void BaseSetupDefaultExpectations() 
    { 
     //Setup default expectations that are general for all views 
     SetupDefaultExpectations(); 
    } 

    protected virtual IDisposable Record() 
    { 
     IDisposable mocksRecordState = _mocks.Record(); 

     BaseSetupDefaultExpectations(); 

     return mocksRecordState; 
    } 

    protected virtual IDisposable Playback() 
    { 
     return _mocks.Playback(); 
    } 

    protected void RaiseEventOnView(string eventName) 
    { 
     (View as IMockedObject).RaiseEvent(eventName); 
    }  
} 

這消除了我們項目中測試的大量代碼。

我們仍然使用舊版本的RhinoMocks,但我會嘗試在我們移到更高版本時更新此版本。