Unable to verify method called via Xunit Mock - c#

Using Moq 4.18.1 to test my C# code, I'm wanting to verify a method calls another method. In the class being tested I have this:
public class IntegratedPlatformRepository : PvRepository<OutputDTO>, IIntegratedPlatformRepository
{
protected virtual async Task IpSpecificGetterExtras(OutputDTO dto, CancellationToken cancellationToken) { }
public async Task<OutputDTO> GetAsync(Guid uid, CancellationToken cancellationToken = default) {
var dto = ...
await IpSpecificGetterExtras(dto, cancellationToken);
...
}
I want to ensure that IpSpecificGetterExtras is called when GetAsync is called, so I tried this:
[Fact]
public async Task GetAsync_Calls_IpSpecificGetterExtras()
{
// Arrange
var mock = new Mock<IntegratedPlatformRepository> {
CallBase = true
};
// Act
await _repo.GetAsync(Guid.NewGuid().ToString());
// Assert
mock
.Protected()
.Verify<Task>(
"IpSpecificGetterExtras", Times.Once(),
ItExpr.IsAny<OutputDTO>(), ItExpr.IsAny<CancellationToken>()
);
}
If I simply run the test it fails saying the invocation wasn't performed. If I debug the test and set a breakpoint in IpSpecificGetterExtras the breakpoint is hit and I can step through the method, so it's definitely being called.

Based on the shown example mock was not invoked.
The test needs to be refactored to allow it to flow to completion so that it can be verified as expected.
[Fact]
public async Task GetAsync_Calls_IpSpecificGetterExtras() {
// Arrange
var mock = new Mock<IntegratedPlatformRepository> {
CallBase = true
};
mock.Protected()
.Setup<Task>("IpSpecificGetterExtras",
ItExpr.IsAny<OutputDTO>(), ItExpr.IsAny<CancellationToken>())
.Returns(Task.CompletedTask);
var subject = mock.Object;
// Act
await subject.GetAsync(Guid.NewGuid().ToString());
// Assert
mock
.Protected()
.Verify<Task>(
"IpSpecificGetterExtras", Times.Once(),
ItExpr.IsAny<OutputDTO>(), ItExpr.IsAny<CancellationToken>()
);
}

Related

How to unit test MassTransit request response

I am trying to test a method that calls Masstransit Request
public async Task<EventsPingCompleted> SendPing()
{
_logger.LogInformation($"Sending Events Ping");
var message = new EventsPing();
var response = await _bus.Request<EventsPing, EventsPingCompleted>(message).ConfigureAwait(false);
return response.Message;
}
I want to return a specific response as part of my unit test. To do this I created a stubbed consumer because I don't want to unit test the consumer, I am doing that in other tests.
public class StubbedConsumer<T,TRt>: IConsumer<T> where T : class where TRt : class
{
private readonly TRt _response;
public StubbedConsumer( TRt expectedResponse )
{
_response = expectedResponse;
}
public async Task Consume(ConsumeContext<T> context)
{
await context.RespondAsync<TRt>(_response).ConfigureAwait(false);
}
}
My unit test is passing but when I debug it the stubbed consumer is being called in my unit test.
[Fact]
public async Task SendPing_GetResponse()
{
// Arrange
var harness = new InMemoryTestHarness();
var expectedResult = new EventsPingCompleted();
var startEvent = new EventsPing();
// the harness needs a consumer for request to work
harness.Consumer(() => new StubbedConsumer<EventsPing, EventsPingCompleted>(expectedResult));
await harness.Start();
// helper needs to be after harness is started
var helper = new PingHelper(harness.BusControl, _logger.Object);
//connect a request client
var requestClient = await harness.ConnectRequestClient<EventsPing>().ConfigureAwait(false);
// Act
// this configures the response, these 2 are equivalent but without calling get response on the request client the tests time out
// when both are called the StubbedConsumer is called twice
var response = await requestClient.GetResponse<EventsPingCompleted>(startEvent);
var result = await helper.SendPing().ConfigureAwait(false);
try
{
// Assert
Assert.True(harness.Sent.Select<EventsPing>().Any());
Assert.True(harness.Consumed.Select<EventsPingCompleted>().Any());
Assert.Equal(expectedResult.Time, result.Time);
Assert.Equal(expectedResult.Time, response.Message.Time);
}
finally
{
await harness.Stop();
}
}
The first message is dispatched by
var response = await requestClient.GetResponse<EventsPingCompleted>(startEvent);
And then the second happens in my system under test
var result = await helper.SendPing().ConfigureAwait(false);
If I remove the call requestClient.GetResponse() the SUT times out without receiving the response from the stubbed consumer.
Is there a way that I can configure the request client without calling GetResponse so that I'm not sending 2 events?

Mock handler with parameter Mediatr and Moq

I'm trying to mock a handler with Moq. This handler takes a parameter of type bool to filter out active customers and non active customers.
The handler is used in my service:
public async Task<IEnumerable<CustomerDto>> GetCustomers(bool active)
{
return _mapper.Map<IEnumerable<CustomerDto>>(await _mediatr.Send(new GetCustomersQuery { Active = active }));
}
My handler looks like this:
public class GetCustomersHandler : IRequestHandler<GetCustomersQuery, IEnumerable<Customer>>
{
private readonly ICustomersRepository _repository;
public GetCustomersHandler(ICustomersRepository repository)
{
_repository = repository;
}
public async Task<IEnumerable<Customer>> Handle(GetCustomersQuery request, CancellationToken cancellationToken)
{
return await _repository.GetCustomers(request.Active);
}
}
My test:
[Fact]
public async Task CustomersService_GetCustomers_ActiveReturnsOnlyActiveCustomers()
{
var result = await _service.GetCustomers(true);
// asserts to test result
}
My mock code:
var mockMediatr = new Mock<IMediator>();
mockMediatr.Setup(m => m.Send(It.IsAny<GetBlockedCustomersAndGroupsQuery>(), It.IsAny<CancellationToken>()))
.Returns(async (bool active) =>
await _getBlockedCustomersAndGroupsHandler.Handle(new GetBlockedCustomersAndGroupsQuery { Active = active }, new CancellationToken())); ---> How can I pass my bool parameter here?
EDIT:
I don't have the mock code for the mediator in my test (for reuse). I want to be able to test both scenarios where true is passed and false is passed. If I try it like mentioned above, I get this error: "Invalid callback. Setup on method with 2 parameter(s) cannot invoke callback with different number of parameters (1)".
I can mock the mediator in the test code and pass that:
mockMediatr.Setup(m => m.Send(It.IsAny<GetBlockedCustomersAndGroupsQuery>(), It.IsAny<CancellationToken>()))
.Returns(async () =>
await _getBlockedCustomersAndGroupsHandler.Handle(new GetBlockedCustomersAndGroupsQuery { Active = true }, new CancellationToken()));
But here I'm not able to reuse it in the second test (with Active = false) and I have some duplicated code. Is there a way to do it like this or do I need to put the mock code inside the test code?
I found how I can access the data that is passed.
mockMediatr.Setup(m => m.Send(It.IsAny(), It.IsAny())) .Returns(async (GetBlockedCustomersAndGroupsQuery q, CancellationToken token) => await _getBlockedCustomersAndGroupsHandler.Handle(new GetBlockedCustomersAndGroupsQuery { Active = q.Active}, token));

How do I unit test a class that depends on TaskCompletionSource?

I have a class that depends on TaskCompletionSource
An example of the class looks like this:
public ExampleClass
{
private TaskCompletionSource<string> _tcs;
public async Task<string> GetFooAsync()
{
_tcs = new TaskCompletionSource<string>();
return await _tcs.Task;
}
public void SetFoo(string value)
{
_tcs.SetResult(value);
}
}
I am using xUnit.net as my testing framework.
[Fact]
public async Task ReturnsString()
{
// Arrange
const string value = "test";
var myclass = new ExampleClass();
// Act -- Does not work. I don't know how to fix this.
var result = await myclass.GetFooAsync(); // Won't return before SetFoo is called
myclass.SetFoo(value); // Needs to be run after GetFooAsync is called
// Assert
Assert.Equal(value, result);
}
(see comments in code)
For this example case, the test needs to be arranged differently
[Fact]
public async Task ReturnsString() {
// Arrange
const string expected = "test";
var sut = new ExampleClass();
var task = sut.GetFooAsync(); // launch tack and do not await
sut.SetFoo(expected); // set expected value after GetFooAsync is called
// Act
var actual = await task;
// Assert
Assert.Equal(expected, actual);
}
The task can be launched and not awaited to allow for the sut to be able to set the task result.
Once the result is set, the task can then be awaited as intended to verify the expected behavior

NSubstitute returning NullReferenceException when Using ForPartsOf and mocking an Async Method

I have two methods:
public class MyClass
{
public virtual async Task MethodOne(MyModel myModel)
{
await Task.Delay(1);
throw new Exception("Test");
}
public async Task MethodTwo()
{
MyModel myModel = new MyModel();
await MethodOne(myModel);
}
}
It doesn't matter what MyModel is, but it does matter that it's a parameter.
And the test:
[Fact]
public async Task Test6()
{
// Arrange
MyClass myClass = Substitute.ForPartsOf<MyClass>();
myClass.When(async a => await a.MethodOne(Arg.Any<MyModel>())).DoNotCallBase();
// Act
await myClass.MethodTwo();
// Assert
}
The test gives a NullReferenceException when the line:
myClass.When(async a => await a.MethodOne(Arg.Any<MyModel>())).DoNotCallBase();
My guess is that it is, in some way, trying to resolve MyModel; however, the same test works, when performed on a synchronous method, or one without a complex parameter.
Can anyone tell me why this error occurs in this way?
Do not await the setup
overridden method needs to return a Task to allow async to flow to completion when invoked in test.
That means the setup needs to be rewritten
[Fact]
public async Task Test6() {
// Arrange
var myClass = Substitute.ForPartsOf<MyClass>();
myClass.MethodOne(Arg.Any<MyModel>()).Returns(Task.FromResult((object)null));
// Act
await myClass.MethodTwo();
// Assert
//...
}

forceclient async call never received

I'm unit testing one of my async methods but it turns out to be a bit tricky.
In my code I execute two actions witch I try to verify with NSubstitute like so
[TestMethod]
public async Task GivenDebatchingHandler_WhenCommandReceived_EventIsPublishedAndStatusUpdated()
{
// arrange
var forceClient = Substitute.For<IForceClient>();
forceClient.UpdateAsync(EntityNames.EventStore, Arg.Any<string>(), Arg.Any<ExpandoObject>()).Returns(info => Task.FromResult(new SuccessResponse { Success = true }));
var messageHandlerContext = Substitute.For<IMessageHandlerContext>();
var handler = new DebatchingHandler(forceClient);
var #event = new KlantManagementEnvelopeCreatedEvent { Header = new Header { MessageId = "UnitTest" } };
var cmd = new PublishMultipleKlantManagementEnvelopeCreatedEventsCommand { EventsLargePayload = new List<KlantManagementEnvelopeCreatedEvent>(new[] { #event }) };
// act
await handler.Handle(cmd, messageHandlerContext).ConfigureAwait(false);
// assert
await messageHandlerContext.Received().Publish(#event, Arg.Any<PublishOptions>()).ConfigureAwait(false);
await forceClient.Received().UpdateAsync(EntityNames.EventStore, "UnitTest", Arg.Any<ExpandoObject>()).ConfigureAwait(false);
}
The publish is received, but the UpdateAsync is not. This is the code under test:
public async Task Handle(PublishMultipleKlantManagementEnvelopeCreatedEventsCommand message, IMessageHandlerContext context)
{
await Task.WhenAll(message.EventsLargePayload.Select(#event => this.ProcessEvent(#event, context))).ConfigureAwait(false);
}
public async Task ProcessEvent(KlantManagementEnvelopeCreatedEvent envelopeCreatedEvent, IMessageHandlerContext context)
{
await context.Publish(envelopeCreatedEvent).ConfigureAwait(false);
var eventStoreRecord = new EventStore__c { Status__c = EventStoreStatus.Published.ToName() };
await this.forceClient.UpdateAsync(EntityNames.EventStore, envelopeCreatedEvent.Header.MessageId, eventStoreRecord).ConfigureAwait(false);
}
Why is the UpdateAsync call never received?
The test has Arg.Any<ExpandoObject>() in the UpdateAsync assert.
Unless EventStore__c in the method under test derives from ExpandoObject then I don't think that assertion would match.
Try using
await forceClient.Received()
.UpdateAsync(EntityNames.EventStore, "UnitTest", Arg.Any<EventStore__c>())
.ConfigureAwait(false);

Categories

Resources