【问题标题】:Setup method to invoke function调用函数的设置方法
【发布时间】:2017-03-14 08:30:21
【问题描述】:

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

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

我希望模拟这个类,并让 Moq 调用我发送到 Execute 的函数作为参数。

我怎么称呼Execute

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

所以我希望 Moq 调用 GetResponse 并返回其值。我该怎么做?

【问题讨论】:

    标签: c# unit-testing moq mstest


    【解决方案1】:

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

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

    【讨论】:

    • 请注意,我向该方法发送了一个异步函数。我无法正确设置它。
    • 好的,我设法使用 Task.FromResult 正确设置它。谢谢。
    • 是的,Task.FromResult() 是要走的路。
    【解决方案2】:

    首先,如果代码本身被嵌入到您的代码中,您就无法模拟它。模拟 GetResponse 只有在它是一些外部组件时才有意义。否则,它属于你的类,它不应该被嘲笑,但应该在单元测试中进行测试。

    要模拟它,重构你的代码类似于这个。

    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 类及其Execute 方法,并且您可以模拟外部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);
        }
    }
    

    【讨论】:

    • 只是指出 - 问题被标记为mstest 而不是nunit :)
    • 我只是想模拟 Executor 来调用 GetResponse。
    • @user6251216:如果executor即将被mock,如果它实现一个接口也可以类似地完成
    猜你喜欢
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    相关资源
    最近更新 更多