调用函数的设置方法

Setup method to invoke function

我的 class 中有一个方法接收函数 (Func) 作为参数:

T Execute<T>(Func<T> func)
{
    ...
    return func();
}

我想模拟这个 class,并让 Moq 调用我作为参数发送给 Execute 的函数。

我怎么称呼Execute:

string result = await executor.Execute(async () => await GetResponse(query));

所以我希望 Moq 调用 GetResponse 并 return 它的值。我该怎么做?

我不完全确定问题是否包含所有信息,因为它真的很简单:

    public interface I
    {
      T Execute<T>(Func<T> func);
    }

    [TestMethod]
    public void TestMethod1()
    {
      var mock = new Mock<I>();
      mock.Setup(x => x.Execute<string>(It.IsAny<Func<string>>())).Returns((Func<string> x) => x());

      Func<string> myFunc = () => "test";

      Assert.AreEqual("test", mock.Object.Execute(myFunc));
    }

首先,如果代码本身被嵌入到您的代码中,您就不能模拟它。模拟 GetResponse 仅当它是某个外部组件时才有意义。否则,它属于您的 class,不应模拟,但应在单元测试中进行测试。

要模拟它,请按照与此类似的方式重构您的代码。

public class Executor
{
    // IResponseProvider has the GetResponse method.
    // This interface can be mocked in test and can be injected in real environment.
    public IResponseProvider ResponseProvider { get; set; }

    public async Task<T> Execute<T>(Func<T> func)
    {
        var response = await ResponseProvider.GetResponse(query);
        // do something with response...
        return func();
    }
}

现在您可以 测试 Executor class 及其 Execute 方法,并且您可以 mock 外部 IResponseProvider 成员在测试环境中做某事:

[TestFixture] // MSTest: [TestClass]
public class ExecutorTest
{
    private Executor executor;
    private Mock<IResponseProvider> responseProviderMock;

    [SetUp] // MSTest: [TestInitialize]
    public void Init()
    {
        // this is not a mock but the class to be tested
        executor = new Executor();

        // the external components can be mocked, though:
        responseProviderMock = new Mock<IResponseProvider>();

        // setup the mock:
        executor.ResponseProvider = responseProviderMock.Object;
        Func<string> mockResponse = () => "dummy mocked response";
        responseProviderMock.Setup(m => m.GetResponse(It.IsAny<MyQueryType>))
            .Returns(Task.FromResult(mockResponse));
    }

    [Test] // MSTest: [TestMethod]
    public async Task ExecuteSuccessTest()
    {
         // Arrange
         Func<int> input = () => 42;

         // Act
         var result = executor.Execute(input);

         // Assert
         Assert.AreEqual(42, result);
         responseProviderMock.Verify(rp => rp.GetResponse(It.IsAny<MyQueryType>(), Times.Once);
    }
}