Reputation: 3
I'm trying to do a test for a unit that is supposed to get all the entities from the database and delete them all. I'm using .NET 8 and CQRS pattern. This is the Command Handler to remove all the entities:
internal sealed class DeleteAllTodosCommandHandler(IApplicationDbContext context) : ICommandHandler<DeleteAllTodosCommand, bool>
{
public async Task<Result<bool>> Handle(DeleteAllTodosCommand request, CancellationToken cancellationToken)
{
var entitiesToRemove = await context.Todos.ToListAsync(cancellationToken);
context.Todos.RemoveRange(entitiesToRemove);
await context.SaveChangesAsync(cancellationToken);
return Result<bool>.Success(true);
}
}
It should be as simple as that: take all the entities from db (there's a global query filter for user id), delete them all and save changes.
In the Unit Test, I'm trying to mock first the behavior of the:
await context.Todos.ToListAsync(cancellationToken);
I'm trying to mock it in that way, but it's not working:
[Fact]
public async Task Handle_ShouldReturnSuccess_WhenTodoExists()
{
// Arrange
var cancellationToken = new CancellationTokenSource().Token;
List<TodoEntity> entities =
[
new() { Title = "Test title", Description = "Test description" },
new() { Title = "Test title2", Description = "Test description2" }
];
_contextMock.Todos.ToListAsync(Arg.Is(cancellationToken))
.Returns(entities);
var command = new DeleteAllTodosCommand();
// Act
var result = await _handler.Handle(command, cancellationToken);
// Assert
Assert.True(result.Data);
}
But it's always returning this error:
NSubstitute.Exceptions.UnexpectedArgumentMatcherException: Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. Do no...
NSubstitute.Exceptions.UnexpectedArgumentMatcherException
Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. Do not use in a Returns() statement or anywhere else outside of a member call.
Correct use:
sub.MyMethod(Arg.Any<string>()).Returns("hi")
Incorrect use:
sub.MyMethod("hi").Returns(Arg.Any<string>())
at NSubstitute.Core.ThreadLocalContext.LastCallShouldReturn(IReturn value, MatchArgs matchArgs)
at NSubstitute.SubstituteExtensions.ConfigureReturn[T](MatchArgs matchArgs, T returnThis, T[] returnThese)
at NSubstitute.SubstituteExtensions.Returns[T](Task`1 value, T returnThis, T[] returnThese)
at Application.UnitTests.Todos.DeleteAllTodosCommandTest.Handle_ShouldReturnSuccess_WhenTodoExists() in /Users/manuelraso/Documents/repo/devops/templates/dotnet-8-minimal-api-cqrs-postgresql/Application.UnitTests/Todos/DeleteAllTodosCommandTest.cs:line 30
at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 276
--- End of stack trace from previous location ---
at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90
I tried to write many variants of that code but it's not working. Before doing that test, I was able to successfully do the test for the DeleteTodo (by id) in that way:
[Fact]
public async Task Handle_ShouldReturnSuccess_WhenTodoExists()
{
// Arrange
var cancellationToken = new CancellationTokenSource().Token;
var entity = new TodoEntity { Title = "Test title", Description = "Test description" };
_contextMock.Todos.FindAsync(Arg.Is(entity.Id), Arg.Is(cancellationToken))
.Returns(entity);
_contextMock.SaveChangesAsync(Arg.Is(cancellationToken))
.Returns(Task.FromResult(1));
var command = new DeleteTodoCommand(entity.Id);
// Act
var result = await _handler.Handle(command, cancellationToken);
// Assert
Assert.True(result.Data);
}
Because the DeleteTodo was done in that way:
internal sealed class DeleteTodoCommandHandler(IApplicationDbContext context) : ICommandHandler<DeleteTodoCommand, bool>
{
public async Task<Result<bool>> Handle(DeleteTodoCommand command, CancellationToken cancellationToken)
{
var entityToRemove = await context.Todos.FindAsync(command.Id, cancellationToken);
if (entityToRemove is null)
{
return Result<bool>.Failure(new ResultError("Not found"));
}
context.Todos.Remove(entityToRemove);
var result = await context.SaveChangesAsync(cancellationToken);
return Result<bool>.Success(result > 0);
}
}
Any idea what am I doing wrong?
Upvotes: 0
Views: 44