【问题标题】:C# Moq - alternatives to CallBase when mocking void functionC# Moq - 模拟 void 函数时 CallBase 的替代品
【发布时间】:2017-08-15 04:39:04
【问题描述】:

CallBase 是Moq (C# 单元测试库)中的一个函数,它允许轻松使用自定义代码挂钩函数调用,同时保留基本函数调用。在this SO post answer 上注明了它的用途和限制。

该帖子提到的主要限制是 CallBase 函数没有为 void 函数实现

例如,假设我们要模拟这个 Component 类:

public class Component
{
    public virtual void Do() { /* code */ }
}

然后我想使用 mock 调用 base 并运行自定义代码...

var mock = new Mock<Component>();
mock.Setup(m => m.Do())
    // preserve base call (NOT AN OPTION SINCE VOID FUNCTION!)
    .CallBase()
    .Callback(() => {/* custom test code */});

// if Do() was not a void function, this would be supported by the library

一种不令人满意的替代方法是通过将 void 函数一分为二来更改我们正在测试的实际代码结构:

public class Component
{
    public virtual void Do() { 
        this.DoInternal();
    }

    internal void DoInternal(){ /* code */ }
}

然后……

var mock = new Mock<Component>();
mock.Setup(m => m.Do())
    .Callback(() => 
    {
        // my custom code...

        // then call base
        mock.Object.DoInternal();
    });

这并不理想,因为它需要修改实际代码设计/结构纯粹是出于可测试性目的,而且如果 CallBase 由 Moq 本机支持,则需要更多的工作/代码。这种解决方法有替代方案吗?也许在库之外实现一个扩展来支持这个:

public static ICallbackResult<TMock> CallBase<TMock>(this ISetup<TMock> @this)
{
    // not implemented - seems difficult given how little Moq 
    // exposes the underlying implementations which it overrides

    // not sure about ICallbackResult<TMock> being what we'd want for return type...
    // the return type of the actual CallBase function is IReturnsResult<TMock>, but
    // that does not make much sense for a void function
}

让我知道你的想法!

【问题讨论】:

    标签: c# .net unit-testing mocking moq


    【解决方案1】:

    模拟上还有一个CallBase 属性。据我所知,它应该与 CallBase() 方法做同样的事情,只是全局用于模拟,但使用Setup() 或类似的东西显式模拟的方法除外。

    这也可能不是最好的解决方案,但您可以使用.CallBase=true; 设置您的模拟,然后对您想要模拟的所有内容使用显式的Setup() 方法调用以恢复默认的模拟行为。

    【讨论】:

    • 我实际上确实在我的模拟中将 CallBase 属性设置为“true”。没错,这意味着在没有对给定函数调用 Setup 的情况下,调用该函数将恢复为实际的基本实现(而不是在模拟为严格时抛出,或者在松散时返回默认值)。不幸的是,这对这种情况没有帮助,因为我们仍然需要调用 Setup 以便我们可以设置模拟 Callback - 从而否定 CallBase 属性行为。
    【解决方案2】:

    不幸的是,截至目前 Moq 没有用于非返回类型方法的 Callbase 逻辑。

    我建议:

    1. 在 GitHub 上提出问题并对此答案发表评论,我会尝试看看它 + 实施
    2. 同时,我建议不要编辑您的普通代码,并在您的测试类中创建一个继承自 Component 的新类,它会公开如下内容

    public void DoInternal(){ base.Do(); }

    然后在你的回电中你可以调用这个。

    【讨论】:

      猜你喜欢
      • 2011-02-18
      • 2010-12-30
      • 2018-10-22
      • 2016-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      相关资源
      最近更新 更多