forceclient async call never received - c#

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

Related

Testing NServiceBus Behavior with custom Handler

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

Unit test - check on Empty

I developed Unit test for my service. Now my test check on inserting Name and 2nd check on a null.
[TestMethod]
public async Task InsertTownName_ReturnTownName()
{
var builder = new RepositoryBuilder<TownRepository>().SetupManager();
using (builder.CreateIsolationScope())
{
var repository = builder.Build();
var townName = "Town" + DateTime.UtcNow.ToString();
await repository.InsertTown(townName);
var connection = builder.TransactionManager.Connection;
var transaction = builder.TransactionManager.Transaction;
var result = await connection.ReadSingleOrDefaultAsync<Town>(x => x.Name == townName, transaction: transaction);
Assert.IsNotNull(result);
Assert.AreEqual(townName, result.Name);
}
}
[TestMethod]
public async Task InsertNullName()
{
var builder = new RepositoryBuilder<TownRepository>().SetupManager();
using (builder.CreateIsolationScope())
{
var repository = builder.Build();
await repository.InsertTown(null);
var connection = builder.TransactionManager.Connection;
var transaction = builder.TransactionManager.Transaction;
var result = await connection.ReadSingleOrDefaultAsync<Town>(x => x.Name == null, transaction: transaction);
Assert.IsNull(result.Name);
Assert.AreEqual(null, result.Name);
}
}
Both of this method works good. Next step I need check on Empty (If in line where user need insert town name - empty name). I have no idea how implement it. Could You recommend to me and could you check 2nd method for working with null. Is it correct unit test? Here my method that I tested
public async Task<int> InsertTown(string townName)
if (String.IsNullOrEmpty(townName))
{
throw new Exception();
}
else
{
var parameters = new { townName };
return await Connection.QueryFirstOrDefaultAsync<int>(Adhoc["AddTown"], parameters, Transaction);
}
Here is an example of what a method with input parameters checking might look like.
public async Task<int> InsertTown(string townName)
{
if (townName == null)
{
throw new ArgumentNullException(nameof(townName));
}
if (string.IsNullOrWhiteSpace(townName))
{
throw new ArgumentException("Parameter cannot be empty", nameof(townName));
}
var parameters = new { townName };
//return await Connection.QueryFirstOrDefaultAsync<int>(Adhoc["AddTown"], parameters, Transaction);
return await Task.Run(() => 42); // for testing puprposes
}
You can test it like this
[TestMethod]
public async Task InsertTown_NullString_ThrowsArgumentNullExceptionAsync()
{
string townName = null;
// var repository = ...;
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() =>
repository.InsertTown(townName));
}
[DataTestMethod]
[DataRow("")]
[DataRow(" ")]
public async Task InsertTown_EmptyString_ThrowsArgumentExceptionAsync(string value)
{
string townName = value;
// var repository = ...;
await Assert.ThrowsExceptionAsync<ArgumentException>(() =>
repository.InsertTown(townName));
}
As mentioned in the comments, it looks like your unit tests are more like integration tests.
In unit tests, you should not access neither real database, work with a network, nor work with a file system.
You have to mock any dependencies. For example with NSubstitute, FakeItEasy or Moq.
Your Connection.QueryFirstOrDefaultAsync method is static, right?
It is highly recommendable to rewrite the code, getting rid of static methods. With the extraction of abstractions to interfaces. Because static methods, like in your case, are untested or difficult to test.

what's wrong with the implementation of this async chain?

I have the code below in a console app. The LookUpUser method gets called and PostAsJsonAsync gets called but breakpoints in the response checking don't get hit afterwards. What am I doing incorrectly in this implementation?
static void Main(string[] args)
{
TestUseCase().GetAwaiter().GetResult();
}
private static async Task TestUseCase()
{
await GetUserGuids();
}
private static async Task GetUserGuids()
{
var userGuids = new List<Guid>();
userGuids.Add(Guid.Parse("7b5cf09c-196c-4e0b-a0e2-0683e4f11213"));
userGuids.Add(Guid.Parse("3a636154-b7fc-4d96-9cd1-d806119ff79f"));
userGuids.ForEach(async x => await LookUpUser(x));
}
private static async Task LookUpUser(Guid adUserGuid)
{
var client = new HttpClientManager().GetHttpClient();
var response = await client.PostAsJsonAsync("api/v1/users/search", new { ADUserGuid = adUserGuid });
if (response.IsSuccessStatusCode)
{
var groups = await response.Content.ReadAsAsync<List<User>>();
}
else //not 200
{
var message = await response.Content.ReadAsStringAsync();
}
}
userGuids.ForEach(async x => await LookUpUser(x));
The delegate in the ForEach is basically a async void (fire and forget)
Consider selecting a collection of Task and then use Task.WhenAll
private static async Task GetUserGuids() {
var userGuids = new List<Guid>();
userGuids.Add(Guid.Parse("7b5cf09c-196c-4e0b-a0e2-0683e4f11213"));
userGuids.Add(Guid.Parse("3a636154-b7fc-4d96-9cd1-d806119ff79f"));
var tasks = userGuids.Select(x => LookUpUser(x)).ToArray();
await Task.WhenAll(tasks);
}
Also assuming HttpClientManager.GetHttpClient() returns a HttpClient there is no need to create multiple instances. on static client should do
static HttpClient client = new HttpClientManager().GetHttpClient();
private static async Task LookUpUser(Guid adUserGuid) {
var response = await client.PostAsJsonAsync("api/v1/users/search", new { ADUserGuid = adUserGuid });
if (response.IsSuccessStatusCode) {
var groups = await response.Content.ReadAsAsync<List<User>>();
} else {
//not 200
var message = await response.Content.ReadAsStringAsync();
}
}
I got it to work by changing the ForEach to:
foreach (var guid in userGuids)
{
await LookUpUserInSecurityApi(guid);
}

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

MStest task result is null

I'm struggling a bit with one of my tests.
Here is the code I'm testing
public async Task Handle(ReceiveEventsFromSalesForceCommand message, IMessageHandlerContext context)
{
var queryResult = await this.GenerateQueryResultAsync(message).ConfigureAwait(false);
await this.DetermineActionAsync(context, queryResult).ConfigureAwait(false);
}
public async Task<QueryResult<EventStore__c>> GenerateQueryResultAsync(ReceiveEventsFromSalesForceCommand message)
{
QueryResult<EventStore__c> queryResult;
if (string.IsNullOrWhiteSpace(message.NextRecordsUrl))
{
queryResult = await this.forceClient.QueryAsync<EventStore__c>(query).ConfigureAwait(false);
this.log.Info($"AFTER: QueryAllAsync<EventStore>(query), found {queryResult?.TotalSize ?? 0} records");
}
else
{
queryResult = await this.forceClient.QueryContinuationAsync<EventStore__c>(message.NextRecordsUrl).ConfigureAwait(false);
this.log.Info("AFTER: QueryContinuationAsync<EventStore>(query)");
}
return queryResult;
}
And this is my unit test
[TestMethod]
public async Task Test()
{
// arrange
var forceConfig = Substitute.For<ISalesForceCreationHandlerConfig>();
var forceClient = Substitute.For<IForceClient>();
forceClient.QueryAllAsync<EventStore__c>(Arg.Any<string>()).Returns(Task.FromResult(new QueryResult<EventStore__c> { NextRecordsUrl = "Dummy" }));
var messageHandlerContext = Substitute.For<IMessageHandlerContext>();
var handler = new SalesForceBatchCreationHandler(forceClient, null, forceConfig);
// act
await handler.Handle(new ReceiveEventsFromSalesForceCommand(), messageHandlerContext);
// assert
await messageHandlerContext.Received().Send(Arg.Is<ReceiveEventsFromSalesForceCommand>(command => string.IsNullOrWhiteSpace(command.NextRecordsUrl)), Arg.Any<SendOptions>());
await messageHandlerContext.DidNotReceive().SendLocal(Arg.Any<PublishMultipleKlantManagementEnvelopeCreatedEventsCommand>());
}
My problem is that iresult of my GenerateQueryResultAsync method is null and I get a NullReferenceException. How can I make sure the result is not null and avoid the Exception?
Restructure the way you make your async calls. Most probably this {queryResult.TotalSize} is the culprit.
public async Task<QueryResult<EventStore__c>> GenerateQueryResultAsync(ReceiveEventsFromSalesForceCommand message) {
QueryResult<EventStore__c> queryResult;
if (string.IsNullOrWhiteSpace(message.NextRecordsUrl)) {
queryResult = await this.forceClient.QueryAsync<EventStore__c>(query).ConfigureAwait(false);
this.log.Info($"AFTER: QueryAllAsync<EventStore>(query), found {queryResult?.TotalSize ?? 0} records");
} else {
queryResult = await this.forceClient.QueryContinuationAsync<EventStore__c>(message.NextRecordsUrl).ConfigureAwait(false);
this.log.Info("AFTER: QueryContinuationAsync<EventStore>(query)" );
}
return queryResult;
}

Categories

Resources