RhinoMocks事件订阅

时间:2008-11-26 16:46:55

标签: asp.net unit-testing rhino-mocks

作为RhinoMocks和Unit Testing的新手,我遇到了一个似乎无法找到解决方案的问题(无论我阅读了多少文档)。

问题是:我创建了一个公开5个事件的接口(用于ASP.NET中的视图和MVP监控模式......我知道,我应该使用MVC,但那是另一个问题)。无论如何,我想测试当某个事件在视图上触发时,我们将其称为“IsLoaded”,调用我的Presenter内部的方法,并使用依赖注入从依赖关系返回一个值并设置为风景。这是问题开始的地方:当我使用Expect.Call(Dependency.GetInfo())。返回(SomeList)时,调用永远不会执行(没有调用mock.ReplayAll()方法)。好吧,当我调用ReplayAll方法时,由于Presenter对象对View接口公开的其他事件的订阅,我得到了ExpectationExceptions。

因此,为了测试IView.IsLoaded已经触发,我想验证IView.ListOfSomething已经更新以匹配我通过Expect.Call()传入的列表。但是,当我设置期望时,其他事件订阅(直接出自Presenter的构造函数)未通过测试的#0期望。我得到的是,view.Save + = this.SaveNewList抛出了RhinoMocks ExpectationViolationException。

我的百万美元问题是这样的:我是否有必要为所有事件设定期望(通过[设置]),或者是否有一些我缺少/不理解单元测试或RhinoMocks如何工作的东西?

请记住,我是非常新的单位测试,因此是RhinoMocks。如果看起来我不知道我在说什么,请随时指出。

1 个答案:

答案 0 :(得分:2)

我正在开展一个我们使用MVP和犀牛模拟的项目。我们所做的只是期望每次测试中的所有事件订阅。

    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,但是一旦我们转移到更高版本,我会尝试更新。