【问题标题】:RhinoMocks Event SubscriptionRhinoMocks 活动订阅
【发布时间】:2008-11-26 16:46:55
【问题描述】:

作为 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。如果我不知道我在说什么,请随时指出。

【问题讨论】:

  • 只是一个更新,因为它可能会帮助遇到同样问题的其他人:我发现了我的致命缺陷。在我的新手方式中,我没有使用 mock.DynamicMock 创建我的视图模拟,而是使用 .CreateMock。傻我。那些“未定义”的方法调用导致了异常。

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


【解决方案1】:

我正在开展一个项目,其中我们也使用了 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,但一旦我们升级到更高版本,我会尝试更新它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 2023-04-08
    • 2023-01-09
    • 2016-06-10
    • 1970-01-01
    相关资源
    最近更新 更多