Testing NServiceBus Behavior with custom Handler - c#

I have a MessageHandler with a custom attribute on it. The behavior I'm testing does something based on the value of that attribute. The NServicebus documentation only gives unit tests examples of a behavior based on a mocked handler. How can I use my own fake or is there an other way I should test my behavior?
// A fake message handler containing the attribute
[ExecuteHandler(true)]
class FakeHandler : IHandleMessages<FakeCommand>
{
public Task Handle(FakeCommand message, IMessageHandlerContext context) => Task.CompletedTask;
}
[Test]
public async Task Invoke_GivenHandlerWithoutAttribute_InvokeNext()
{
// Given
var handlerExecuted = false;
var context = new TestableMessageHandlerContext
{
// I want to add my fake handler to the context so I can test if it gets executed. Problem is that I can't cast my handler to type MessageHandler
// MessageHandler = new FakeHandler(),
}
// When
await _behavior.Invoke(context, () =>
{
handlerExecuted = true;
return Task.CompletedTask;
});
// Then
handlerExecuted.Should().BeTrue();
}

To answer my own question. I made it work by letting my handlers inherit MessageHandler.
[Test]
public async Task Invoke_GivenHandlerWithAttributeTrue_InvokeNext()
{
// Given
var handlerExecuted = false;
var context = new TestableMessageHandlerContext
{
MessageHandler = new MessageHandler(null, typeof(FakeHandler)),
}
// When
await _behavior.Invoke(context, () =>
{
handlerExecuted = true;
return Task.CompletedTask;
});
// Then
handlerExecuted.Should().BeTrue();
}
[Test]
public async Task Invoke_GivenHandlerWithAttributeFalse_DoesNotInvokeNext()
{
// Given
var handlerExecuted = false;
var context = new TestableMessageHandlerContext
{
MessageHandler = new MessageHandler(null, typeof(FakeHandlerNotExecuting)),
}
// When
await _behavior.Invoke(context, () =>
{
handlerExecuted = true;
return Task.CompletedTask;
});
// Then
handlerExecuted.Should().BeFalse();
}
[ExecuteHandler(true)]
class FakeHandler: IHandleMessages<FakeCommand>
{
public Task Handle(FakeCommand message, IMessageHandlerContext context) => Task.CompletedTask;
}
[ExecuteHandler(false)]
class FakeHandlerNotExecuting: IHandleMessages<FakeCommand>
{
public Task Handle(FakeCommand message, IMessageHandlerContext context) => Task.CompletedTask;
}

Related

How can I return Task<bool> from a Mock method using Xunit and Moq

I have this Repository class
public class ComplaintRepository : IComplaintRepository
{
private readonly IAppDbContext _context;
public ComplaintRepository(IAppDbContext context)
{
_context = context;
}
public async Task<bool> AddAsync(Complaint complaint, CancellationToken token)
{
await Task.Run(() => _context.Complaints.AddAsync(complaint));
return await SaveAsync(token);
}
private async Task<bool> SaveAsync(CancellationToken token)
{
if (await _context.SaveChangesAsync(token) > 0)
return true;
else
return false;
}
I want to set up a test for the class using xUnit and Moq. When I mock the behavior of the AddAsync method like so:
public class ComplaintRepositoryTests
{
[Fact]
public async void AddAsync_WithValidComplaint_ShouldReturnTrue()
{
// Arrange
var mockContext = new Mock<IAppDbContext>();
mockContext.Setup(x => x.Complaints.AddAsync(It.IsAny<Complaint>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(true));
mockContext.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(1);
var complaintRepository = new ComplaintRepository(mockContext.Object);
var complaint = new Complaint();
// Act
var result = await complaintRepository.AddAsync(complaint, CancellationToken.None);
// Assert
Assert.True(result);
mockContext.Verify(x => x.Complaints.AddAsync(It.IsAny<Complaint>(), It.IsAny<CancellationToken>()), Times.Once());
mockContext.Verify(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
}
I am getting an error for the return type of the AddAsync method.
this is the error I am getting:
cannot convert from 'System.Threading.Tasks.Task<bool>' to 'System.Threading.Tasks.ValueTask<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<CCMP.Domain.Complaints.Complaint>>'
I don't know how to go about it. I have tried all the things I have seen online to no avail.

Masstransit Problem adding Payload to request/response in Unit Testing, alternativly using Pipes in Unit Tests

currently I have the problem that I want to write unit tests for Masstransit in .NET. My request/response consumer has some consumer filters, one of these filters are generating extra data as message payload and attaching this to the request message. In order to test my consumer in a unit test I would like to add the Payload.
Q1) Is it possible to add the payload to the request message
Q2) Alternativly, can I make a mocking filter and set it as consumer filter in the pipeline? (Which sets the payload)
This is my latest attempt:
public class ContactCommandConsumerTest
{
[Fact]
public async Task CreateContactOnUserRequestConsumer_RequestConsumer_IsAttached()
{
var harness = new InMemoryTestHarness { TestTimeout = TimeSpan.FromSeconds(5) };
[...]
var consumer = harness.Consumer<CreateContactOnUserRequestCommandConsumer>(() => new CreateContactOnUserRequestCommandConsumer(loggerConsumer, mapper,kontakteintragRep,machineTime));
var pipe = Pipe.New<PipeContext>(x => x.UseFilter(new MockFilter<PipeContext>()));
// harness.Consumer<CreateContactOnUserRequestCommandConsumer>();
await harness.Start();
try
{
harness.Bus.ConnectConsumePipe<CreateContactOnUserRequestCommandConsumer>(pipe);
var requestClient = await harness.ConnectRequestClient<CreateContactOnUserRequestCommand>();
var response = await requestClient.GetResponse<AcceptedResponse, FaultedResponse>(new
{
EntityInfo = "Vb48cc135-4593-4b96-bb29-2cf136b3d1ee",
});
Assert.True(consumer.Consumed.Select<CreateContactOnUserRequestCommand>().Any());
Assert.True(harness.Sent.Select<FaultedResponse>().Any());
}
finally
{
await harness.Stop();
}
}
}
internal class MockFilter<T> : IFilter<T> where T: class, PipeContext
{
public void Probe(ProbeContext context)
{
context.CreateFilterScope("mock");
}
public async Task Send(T context, IPipe<T> next)
{
context.GetOrAddPayload(() => new ContextUserPayload() { ContextUser = new Guid("dc6e091f-669e-45b3-9dd6-a36316f70527") });
await next.Send(context);
}
}
I tried to build a pipe and add it to "harness.bus.ConnectConsumerPipe". But the mock filter is never called ???
You use use the OnConfigureInMemoryBus event on the InMemoryTestHarness to add your filter to the bus endpoint.
Similar to:
harness.OnConfigureInMemoryBus += configurator =>
{
configurator.UseFilter(...);
}
To add a filter to the request, use:
using RequestHandle<TRequest> requestHandle = requestClient.Create(message, cancellationToken);
requestHandle.UseFilter(...);
return await requestHandle.GetResponse<TResponse>().ConfigureAwait(false);

Moq Raise for an async event listener

in WPF, I am trying to use moq to raise an event that has an async listener hooked to it:
My code:
public class Provider
{
private IService _service
public Provider(IService service)
{
_service = service;
_service.OnResultsChanged += ChangeResults;
}
private async void ChangeResults(List resultsAdded)
{
await Task.Run(() => HasResults = true;)
}
}
For simplification, i've set hasresults to true, but I am really adding items to a list and as this operation could take a while, I am doing it in a new task. In my test, the following fails, as it doesn't wait for the DoSomething execution:
My test:
[Test]
public void Test()
{
//Arrange
var serviceMock = new Mock<IService>();
var systemUnderTest = new Provider(serviceMock .Object);
//Act
serviceMock.Raise(mock => mock.OnResultsChanged += null);
//Assert
Assert.IsTrue(systemUnderTest.HasResults);
}
is it possible to tell mock.raise to await the execution of my event listener?
Thanks!
You can convert the test to be async as well and await a delayed task to allow the async event handler to perform its functionality.
The following example uses a delay in the even handler to simulate a potential long running task.
public interface IService {
event EventHandler OnResultsChanged;
}
public class Provider {
private IService _service;
public Provider(IService service) {
_service = service;
_service.OnResultsChanged += ChangeResults;
}
private async void ChangeResults(object sender, EventArgs e) {
await Task.Delay(200); //<-- simulate delay
await Task.Run(() => HasResults = true);
}
public bool HasResults { get; set; }
}
By converting the test to async and waiting for the raised event, the assertion was able to be asserted.
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Test() {
//Arrange
var serviceMock = new Mock<IService>();
var systemUnderTest = new Provider(serviceMock.Object) {
HasResults = false
};
//Act
serviceMock.Raise(mock => mock.OnResultsChanged += null, EventArgs.Empty);
await Task.Delay(300); //<--wait
//Assert
Assert.IsTrue(systemUnderTest.HasResults);
}
}

Getting result from Func<Task<T>>

Method Under Test
protected override async Task<Name> DoExecuteAsync(NameContext context)
{
context.ThrowIfNull("context");
var request = new Request
{
Id = context.Id,
Principal = context.UserPrincipal,
};
return await this.repository.NameAsync(request, new CancellationToken(), context.ControllerContext.CreateLoggingContext());
}
protected override Name HandleError(NameContext viewContext, Exception exception)
{
if (this.errorSignaller != null)
{
this.errorSignaller.SignalFromCurrentContext(exception);
}
return Name.Unknown;
}
This is implementation of
public abstract class BaseQueryAsync<TInput, TOutput> : IQueryAsync<TInput, TOutput>
{
public async Task<TOutput> ExecuteAsync(TInput context)
{
try
{
return await this.DoExecuteAsync(context);
}
catch (Exception e)
{
return this.HandleError(context, e);
}
}
protected abstract Task<TOutput> DoExecuteAsync(TInput context);
protected virtual TOutput HandleError(TInput viewContext, Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
Test Case goes like below
[SetUp]
public void Setup()
{
var httpContext = MvcMockHelpers.MockHttpContext(isAuthenticated: true);
this.controller = new Mock<Controller>();
this.controller.Object.SetMockControllerContext(httpContext.Object);
this.repoMock = new Mock<IRepository>();
this.errorSignaller = new Mock<IErrorSignaller>();
this.query = new NameQuery(this.repoMock.Object, this.errorSignaller.Object);
this.userPrinciple = new Mock<IPrincipal>();
this.context = new NameContext(this.controller.Object.ControllerContext, this.userPrinciple.Object);
}
[Test]
public async Task TestDoExecuteAsyncWhenRepositoryFails()
{
// Arrange
this.repoMock.Setup(
x => x.NameAsync(
It.IsAny<Request>(),
It.IsAny<CancellationToken>(),
It.IsAny<ILoggingContext>())).Throws<Exception>();
// Act
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
// Assert
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
}
To verify the Name Object ,When I use the var result = await act() before the line
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
The this.errorSignaller.Verify fails since it's count is 2 instead of 1. My intention is to check the Name object along with below code.
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
I knew that if I write a new test case I can easily verify it, but is there any way I can do altogether in this test?
If you want to test the result then use:
Name result = await this.query.ExecuteAsync(this.context);
result.Should().Be(expectefResult);
Make sure to make your test method public async Task
Update
To be able to verify name you would need to set it in the function.
//...code removed for brevity
Name expectedName = Name.Unknown;
Name actualName = null;
// Act
Func<Task> act = async () => {
actualName = await this.query.ExecuteAsync(this.context);
};
// Assert
act.ShouldNotThrow();
actualName
.Should().NotBeNull()
.And.Be(expectedName);
//...rest of code
Original
As already mentioned in the comments, act is a function that returns a Task.
While its implementation is awaited, the function itself still needs to be invoked. And since the function returns a Task it too would need to be awaited.
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
var name = await act();
It is the same as having the following function.
async Task<Name> act() {
return await this.query.ExecuteAsync(this.context);
}
You would have to await it the same way
var name = await act();
The only difference being that the former example has the function in a delegate.
Try to avoid mixing blocking calls like .Result with async/await code. This tends to cause deadlocks.
You can try to check it with
await query.ExecuteAsync(this.context);
or
this.query.ExecuteAsync(this.context).GetAwaiter().GetResult();
and in case of Func:
act.Invoke().GetAwaiter().GetResult();

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