【问题标题】:How to execute a generic func that is passed as a parameter to a mocked service如何执行作为参数传递给模拟服务的通用函数
【发布时间】:2019-01-06 06:55:31
【问题描述】:

我有一个在单独的库中实现的服务,并将Func<T> 作为函数的参数。

在模拟服务时,我仍然需要运行 Func<T>

如何为此设置模拟对象?

我创建了以下代码示例来演示该问题:

// This is the service that is in a different library and I want to mock
public interface IServiceToMock
{
    T ExecuteAsync<T>(Func<T> func);
}

public class ServiceToMock : IServiceToMock
{
    public T ExecuteAsync<T>(Func<T> funcToBeExecuted)
    {
        // does some more logic that I don't want to test
        return funcToBeExecuted();
    }
}

这是服务的消费者

public class ServiceConsumer
{
    private readonly IServiceToMock service;

    public ServiceConsumer(IServiceToMock service) => this.service = service;

    public async Task Consume()
    {
        await service.ExecuteAsync(async () => await ConsumeInteger(1));
        await service.ExecuteAsync(async () => await ConsumeString("String"));
    }

    // This is the method that I want to be triggered when the Consume() is called
    private async Task ConsumeInteger(int number)
    {
        await new Task<int>(() =>
        {
            Console.WriteLine(number);
            return number;
        });
    }

    // This is the method that I want to be triggered when the Consume() is called
    private async Task ConsumeString(string str)
    {
        await new Task<string>(() =>
        {
            Console.WriteLine(str);
            return str;
        });
    }
}

这是我目前的测试

public class TestServiceConsumer
{
    public void TestMethod()
    {
        var moqLibraryService = new Mock<IServiceToMock>();
        // How can I set up the mock to have the Console 
        moqLibraryService.Setup(ms => ms.ExecuteAsync(It.IsAny<Func<T>>())).Returns(T());
    }
}

【问题讨论】:

  • 有什么问题?
  • 你能用Callback()吗?
  • 问题是你不能模拟一个通用的 Funct 返回。所以测试的最后一行不起作用。为了绕过这个,从 IServiceToMock 创建了一个存根,它正在调用 Func 而没有做任何其他事情。

标签: c# moq


【解决方案1】:

我认为你可以这样做:

var moqLibraryService = new Mock<IServiceToMock>();

moqLibraryService.Setup(ms => ms.ExecuteAsync(It.IsAny<Func<int>>()))
  .Returns( (Func<int> f) => f() );
moqLibraryService.Setup(ms => ms.ExecuteAsync(It.IsAny<Func<string>>()))
  .Returns( (Func<string> f) => f() );

它使用Returns 的重载,它接收valueFunction 而不仅仅是value。每次模拟完成时,匿名函数(Func&lt;int&gt; f) =&gt; f() 将再次被评估。这里f 是传递给 Moq 的任意参数。

如果您不想明确提及类型(此处为intstring),可能会更难做到。这将与线程 Mocking generic methods in Moq without specifying T 有关。

【讨论】:

  • 这是个好主意,但实际上服务有点多,所以使用存根的简单方法。
猜你喜欢
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
  • 2013-01-27
  • 2020-06-07
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多