使用Moq模拟Func <>构造函数参数并验证它是否被调用了两次

the*_*ead 26 c# unit-testing moq functional-testing

从这篇文章中获取问题(How to moq a Func)并对其进行了调整,因为答案是不正确的.

public class FooBar
{
    private Func<IFooBarProxy> __fooBarProxyFactory;

    public FooBar(Func<IFooBarProxy> fooBarProxyFactory)
    {
        _fooBarProxyFactory = fooBarProxyFactory;
    }

    public void Process() 
    {
        _fooBarProxyFactory();
        _fooBarProxyFactory();
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要模拟一个作为构造函数参数传递的Func <>,断言func被调用两次.

当试图模拟函数时var funcMock = new Mock<Func<IFooBarProxy>>();Moq引发异常,因为Func类型不可模拟.

问题是,如果没有模拟func,就不可能验证函数被调用(n)次. funcMock.Verify( (), Times.AtLeast(2));

Dan*_*rth 33

我认为没有必要为Func使用模拟.

您可以自己创建一个普通的Func,返回一个模拟IFooBarProxy:

int numberOfCalls = 0;
Func<IFooBarProxy> func = () => { ++numberOfCalls;
                                  return new Mock<IFooBarProxy>(); };

var sut = new FooBar(func);

sut.Process();

Assert.Equal(2, numberOfCalls);
Run Code Online (Sandbox Code Playgroud)


kta*_*m33 22

至少从Moq 4.5.28开始,你可以像你期望的那样模拟和验证Func.我无法分辨这个功能何时被添加(根据原始问题在某些时候这不起作用).

[Test]
public void TestFoobar()
{
    var funcMock = new Mock<Func<IFooBarProxy>>();
    var fooBar = new FooBar(funcMock.Object);
    fooBar.Process();
    funcMock.Verify(x => x(), Times.AtLeast(2));
}
Run Code Online (Sandbox Code Playgroud)


huy*_*itw 7

最小订量 v4.1.1308.2120

在提出这个问题几个月后发布的这个版本(2013 年 8 月 21 日),Func<> 已经添加了模拟 a 的功能。因此,对于任何当前版本的模拟,您都可以使用var funcMock = new Mock<Func<IFooBarProxy>>();.

原始(过时)答案

如果你有很多回调Func的,Actions等等,这是更好地定义你的测试一个助手接口和模拟该接口。通过这种方式,您可以使用常规的 Moq 功能,例如设置返回值、测试输入参数等。

interface IFooBarTestMethods
{
    IFooBarProxy FooBarProxyFactory();
}
Run Code Online (Sandbox Code Playgroud)

用法

var testMethodsMock = new Mock<IFooBarTestMethods>();
testMethodsMock
    .Setup(x => x.FooBarProxyFactory())
    .Returns(new Mock<IFooBarProxy>());

var sut = new FooBar(testMethodsMock.Object.FooBarProxyFactory);
testMethodsMock.Verify(x => x.FooBarProxyFactory(), Times.Exactly(2));
Run Code Online (Sandbox Code Playgroud)