如何在 xUnit 中模拟委托

How to mock Delegate in xUnit

我有调用 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();
    }

你不能嘲笑代表。你也不能嘲笑那个表达式,因为它被硬编码到被测对象中。

您需要在 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 正在做什么以确保可以通过其调用模拟安全路径。