简体   繁体   English

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

[英]Using Moq to Mock a Func<> constructor parameter and Verify it was called twice

Taken the question from this article ( How to moq a Func ) and adapted it as the answer is not correct.从这篇文章( How to moq a Func )中提取问题并将其改编为答案不正确。

public class FooBar
{
    private Func<IFooBarProxy> __fooBarProxyFactory;

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

    public void Process() 
    {
        _fooBarProxyFactory();
        _fooBarProxyFactory();
    }
}

I have a need to mock a Func<> that is passed as a constructor parameter, the assert that the func was call twice.我需要模拟作为构造函数参数传递的 Func<>,即 func 被调用两次的断言。

When trying to mock the function var funcMock = new Mock<Func<IFooBarProxy>>();当试图模拟函数时var funcMock = new Mock<Func<IFooBarProxy>>(); Moq raises and exception as the Func type is not mockable. Moq 引发和异常,因为 Func 类型不可模拟。

The issue is that without mocking the func it is not possible to verify that the func was called (n) times.问题是,如果不模拟函数,就无法验证函数是否被调用 (n) 次。 funcMock.Verify( (), Times.AtLeast(2));

I don't think it is necessary to use a mock for the Func. 我认为没有必要为Func使用模拟。

You can simply create an ordinary Func yourself that returns a mock of IFooBarProxy : 您可以自己创建一个普通的Func,返回一个IFooBarProxy的模拟:

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

var sut = new FooBar(func);

sut.Process();

Assert.Equal(2, numberOfCalls);

As of at least Moq 4.5.28, you can mock and verify the Func as you would expect to be able to. 至少从Moq 4.5.28开始,你可以像你期望的那样模拟和验证Func。 I couldn't tell when this feature was added (according to the original question at some point this did not work). 我无法分辨这个功能何时被添加(根据原始问题在某些时候这不起作用)。

[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));
}

Since Moq v4.1.1308.2120 自Moq v4.1.1308.2120

As of this version, which was released some months after this question was asked (Aug 21, 2013), the functionality to mock a Func<> has been added . 在这个问题(2013年8月21日)被提出几个月之后发布的这个版本中, 添加了模拟Func<>Func<> So with any current version of mock, you can use var funcMock = new Mock<Func<IFooBarProxy>>(); 因此,对于任何当前版本的mock,您可以使用var funcMock = new Mock<Func<IFooBarProxy>>(); .

Original (outdated) answer 原始(过时)的答案

If you have a lot of callback Func 's, Actions , etc, it's better to define a helper interface in your tests and mock that interface. 如果你有很多回调FuncActions等,最好在你的测试中定义一个帮助器接口并模拟该接口。 This way you can use the regular Moq functionality, like setting up return values, testing input arguments, etc. 这样您就可以使用常规Moq功能,例如设置返回值,测试输入参数等。

interface IFooBarTestMethods
{
    IFooBarProxy FooBarProxyFactory();
}

Usage 用法

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));

For Complex scenario like the below one对于像下面这样的复杂场景

 public interface ISqlConnector
    {
        Task<int> ConnectAsync(Func<IDbConnection, Task<int>> performDatabaseOperationAsync, string connectionString);
    }

You can use您可以使用

 var funcMock = new Mock<Func<IDbConnection,Task<int>>>();
            //setup Mock
            sqlConnector.Setup(a => a.ConnectAsync(funcMock.Object, It.IsAny<string>()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM