2008-11-26 136 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,但我会尝试在我们移到更高版本时更新此版本。