2

作为 RhinoMocks 和单元测试的新手,我遇到了一个似乎无法解决的问题(无论我阅读了多少文档)。

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

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

我的百万美元问题是:我是否有必要为我的所有事件设定期望(通过 [Setup]),还是我缺少/不了解单元测试或 RhinoMocks 的工作原理?

请记住,我对单元测试非常陌生,因此对 RhinoMocks 也很陌生。如果看起来我不知道我在说什么,请随时指出。

4

1 回答 1

2

我正在做一个项目,我们也使用了 MVP 和 rhino 模拟。我们所做的只是期望每个测试中的所有事件订阅。

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

于 2008-12-03T14:33:49.307 回答