C#Moq-模拟void函数时CallBase的替代方案

C#Moq-模拟void函数时CallBase的替代方案,c#,.net,unit-testing,mocking,moq,C#,.net,Unit Testing,Mocking,Moq,CallBase是(一个C#单元测试库)中的一个函数,它允许使用自定义代码轻松地连接到函数调用,同时还保留了基本函数调用。会议注意到了它的用途和局限性 这篇文章提到的主要限制是CallBase函数没有为void函数实现 例如,假设我们要模拟此组件类: public class Component { public virtual void Do() { /* code */ } } 然后我想使用mock调用base并运行自定义代码 var mock = new Mock<Comp

CallBase是(一个C#单元测试库)中的一个函数,它允许使用自定义代码轻松地连接到函数调用,同时还保留了基本函数调用。会议注意到了它的用途和局限性

这篇文章提到的主要限制是CallBase函数没有为void函数实现

例如,假设我们要模拟此组件类:

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
然后

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

        // then call base
        mock.Object.DoInternal();
    });
var mock=new mock();
mock.Setup(m=>m.Do())
.Callback(()=>
{
//我的自定义代码。。。
//然后呼叫基地
mock.Object.DoInternal();
});
这并不理想,因为它需要修改实际的代码设计/结构,纯粹是为了可测试性的目的,并且比Moq本机支持CallBase时所需的工作量/代码还要多。除了这项工作,还有其他选择吗?也许在库之外实现一个扩展来支持这一点:

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
}
publicstaticicallbackresult调用库(this-ISetup@this)
{
//未实施-鉴于最低起订量太少,似乎很难实施
//公开它覆盖的底层实现
//不确定ICallbackResult是否是我们想要的返回类型。。。
//实际CallBase函数的返回类型为IReturnsResult,但
//对于空函数来说,这没有多大意义
}

让我知道你的想法

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


这可能不是最好的解决方案,但您可以使用
.CallBase=true
然后使用显式的
Setup()
方法调用希望mocked返回默认mocked行为的所有对象

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


这可能不是最好的解决方案,但您可以使用
.CallBase=true
然后使用显式的
Setup()
方法调用希望mocked返回默认mocked行为的所有对象

不幸的是,到目前为止,
Moq
没有用于非返回类型方法的Callbase逻辑

我建议:

  • 在GitHub上提出一个问题,并对这个答案发表评论,我将尝试查看它+实现
  • 同时,我建议不要编辑您的普通代码,并在您的测试类中创建一个继承自
    组件的新类,该类公开如下内容
  • public void DoInternal(){base.Do();}


    然后在您的回调中可以调用它。

    不幸的是,到目前为止,
    Moq
    没有用于非返回类型方法的Callbase逻辑

    我建议:

  • 在GitHub上提出一个问题,并对这个答案发表评论,我将尝试查看它+实现
  • 同时,我建议不要编辑您的普通代码,并在您的测试类中创建一个继承自
    组件的新类,该类公开如下内容
  • public void DoInternal(){base.Do();}


    然后在您的回调中,您可以调用它。

    实际上,我的模拟中的CallBase属性设置为“true”。您是对的,这意味着在没有对给定函数调用Setup的情况下,调用该函数会恢复到实际的基本实现(而不是在mock严格时抛出,或者在松散时返回默认值)。不幸的是,这对这个场景没有帮助,因为我们仍然需要调用Setup,以便设置模拟回调-从而否定CallBase属性行为。实际上,我的mock上的CallBase属性设置为“true”。您是对的,这意味着在没有对给定函数调用Setup的情况下,调用该函数会恢复到实际的基本实现(而不是在mock严格时抛出,或者在松散时返回默认值)。不幸的是,这对这个场景没有帮助,因为我们仍然需要调用Setup,这样我们就可以设置模拟回调,从而否定CallBase属性行为。
    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
    }