简体   繁体   中英

How to mock Delegate in xUnit

I have delegate that call SendMessagesAsync method which takes IEnumerable ProviderExemptionReceivedNotification. How I mock SendMessagesAsync that is callBack of delegate. In other word how I moq Delegate?

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

You can't mock a delegate. You cant mock that expression either since it is hard-coded into the subject under test.

You need to capture the delegate in a Moq Callback and invoke it there. That is the only option available given the shown subject under test.

Here is an oversimplified minimum reproducable example of a subject under test based on your previous posts.

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

The test for the subject provided above, which includes the Callback capturing the delegate (handler) and invoking it, actually runs as expected when exercsed.

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

You will need to adapt this example to what you are trying to do. It won't copy exactly as written here.

You may still run into problem since you have not shown what SendMessagesAsync is doing to ensure that a safe path can be mocked through its invocation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM