【问题标题】:How to mock Delegate in xUnit如何在 xUnit 中模拟委托
【发布时间】:2022-01-13 15:49:56
【问题描述】:

我有委托调用 SendMessagesAsync 方法,该方法采用 IEnumerable ProviderExemptionReceivedNotification。我如何模拟作为委托回调的 SendMessagesAsync。换句话说,我如何起订委托?

Interface

public delegate Task<bool> SendAnprProviderExemptionNotifications(IEnumerable<ProviderExemptionReceivedNotification> exemptions);

public interface IRingGoApiService
{
    Task<RingGoMessageResponseResult> ProcessCreateRequestAsync(RingGoExemption ringGoExemption, SendAnprProviderExemptionNotifications sendProviderExemption);
}

Delegate Implementation

public async Task<RingGoMessageResponseResult> ProcessCreateRequestAsync(RingGoExemption ringGoExemption, SendAnprProviderExemptionNotifications sendProviderExemption)
    {
       var msgSent = await sendProviderExemption(new List<ProviderExemptionReceivedNotification>() { exemption });
    }

Test Class

public MyTestClass{
 
public MyTestClass()
{
}

private readonly Mock<IProviderExemptionService> providerExemptionServiceMoq;
}

using delegate

var result = await _ringGoApiService.ProcessCreateRequestAsync(ringGoExemption,
async (IEnumerable<ProviderExemptionReceivedNotification> exemptions) => await SendMessagesAsync(servicebusMessage, exemptions)
                    );

SendMessagesAsync

static async Task<bool> SendMessagesAsync(IAsyncCollector<Message> collector, IEnumerable<ProviderExemptionReceivedNotification> exemptions)
    {
        SetProviderExemption(exemptions);

        var messages = exemptions.Select(exemption =>
        {
            //Creating ServiceBus Message...

            return message;
        });
    }

    static void SetProviderExemption(IEnumerable<ProviderExemptionReceivedNotification> exemptions)
    {
        providerExemption = exemptions.FirstOrDefault();
    }

【问题讨论】:

  • 你不能模拟委托。但是您可以在测试代码中创建一个委托,只要它与SendAnprProviderExemptionNotifications 具有相同的签名,它就可以执行您想要的任何操作,并将其作为参数传递给您正在测试的方法。
  • 参考我的问题中的部分using delegate 有 lambda 表达式 SendMessageAsync .. 那么我如何模拟呢?
  • 您也不能模拟该表达式,因为它被硬编码到表达式中。您需要在回调中捕获委托并在那里调用它。鉴于显示的测试对象,这是唯一可用的选项。
  • 你能在语法上帮我吗.. 我在设置中的 SendMessagesAsync(servicebusMessage, excludes) 回调上苦苦挣扎
  • ringGoApiServiceMoq.Setup(x => x.ProcessCreateRequestAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(ringGoMessageResponseResultMoq) .Callback(providerExemptionReceivedNotificationMoq));

标签: c# .net-core delegates xunit


【解决方案1】:

您不能模拟委托。你也不能模拟那个表达式,因为它被硬编码到被测对象中。

您需要在 Moq Callback 中捕获委托并在那里调用它。鉴于显示的测试对象,这是唯一可用的选项。

根据您之前的帖子,这是一个被测试主题的过度简化的最小可重现示例。

public delegate Task<bool> SendAnprProviderExemptionNotifications(IEnumerable<ProviderExemptionReceivedNotification> exemptions);

public interface IRingGoApiService {
    Task<RingGoMessageResponseResult> ProcessCreateRequestAsync(RingGoExemption ringGoExemption, SendAnprProviderExemptionNotifications sendProviderExemption);
}

public class RingGoMessageResponseResult { }

public class ProviderExemptionReceivedNotification { }

public class RingGoExemption : Exception { }

public interface IActionResult { }

public class OverSimplifiedExample {
    private readonly IRingGoApiService ringGoApiService;

    public OverSimplifiedExample(IRingGoApiService ringGoApiService) {
        this.ringGoApiService = ringGoApiService;
    }

    public async Task<bool> Run() {

        RingGoExemption ringGoExemption = new RingGoExemption();

        RingGoMessageResponseResult result = await ringGoApiService.ProcessCreateRequestAsync(ringGoExemption, myDelegate);

        return result != null;
    }

    private Task<bool> myDelegate(IEnumerable<ProviderExemptionReceivedNotification> exemptions) {
        return Task.FromResult(true);
    }
}

上面提供的主题的测试,包括Callback 捕获委托(处理程序)并调用它,实际上在执行时按预期运行。

[TestFixture]
public class MyTestClass {
    [Test]
    public async Task MyTestMethod() {
        //Arrange
        Mock<IRingGoApiService> mock = new Mock<IRingGoApiService>();
        RingGoMessageResponseResult ringGoMessageResponseResult = new RingGoMessageResponseResult();

        mock
            .Setup(_ => _.ProcessCreateRequestAsync(It.IsAny<RingGoExemption>(), It.IsAny<SendAnprProviderExemptionNotifications>()))
            .ReturnsAsync(ringGoMessageResponseResult)
            .Callback((RingGoExemption exception, SendAnprProviderExemptionNotifications handler) => {
                var whateverMyExemptionsAre = Enumerable.Empty<ProviderExemptionReceivedNotification>();
                handler.Invoke(whateverMyExemptionsAre);
            });

        var subject = new OverSimplifiedExample(mock.Object);

        //Act
        var actual = await subject.Run();

        //Assert
        actual.Should().BeTrue();
    }
}

您需要根据您的尝试调整此示例。它不会完全按照这里写的那样复制。

您可能仍然会遇到问题,因为您没有展示 SendMessagesAsync 正在做什么来确保可以通过其调用来模拟安全路径。

【讨论】:

  • 非常感谢您的支持。我通过代码。我还更新了 SendMessagesAsync 实现的问题
  • @Toxic 您基本上需要做的是确保模拟所有与SendMessageAsync 交互的依赖项,以允许测试安全地完成。
  • 非常感谢您的支持。我已经成功地进行了正确的回调
猜你喜欢
  • 2022-11-19
  • 2010-10-05
  • 2011-04-24
  • 1970-01-01
  • 2019-11-24
  • 2021-01-09
  • 1970-01-01
  • 2012-07-05
  • 2019-10-07
相关资源
最近更新 更多