Проблема с ToListAsync() и NSubstitute для UnitTestC#

Место общения программистов C#
Ответить
Anonymous
 Проблема с ToListAsync() и NSubstitute для UnitTest

Сообщение Anonymous »

Я пытаюсь провести тест для модуля, который должен получить все объекты из базы данных и удалить их все.
Я использую .NET 8 и шаблон CQRS.
Это — это обработчик команд для удаления всех объектов:

Код: Выделить всё

internal sealed class DeleteAllTodosCommandHandler(IApplicationDbContext context) : ICommandHandler
{
public async Task Handle(DeleteAllTodosCommand request, CancellationToken cancellationToken)
{
var entitiesToRemove = await context.Todos.ToListAsync(cancellationToken);
context.Todos.RemoveRange(entitiesToRemove);
await context.SaveChangesAsync(cancellationToken);

return Result.Success(true);
}
}
Все должно быть так просто: возьмите все объекты из базы данных (есть глобальный фильтр запросов для идентификатора пользователя), удалите их все и сохраните изменения.
В модульном тесте я сначала пытаюсь имитировать поведение:

Код: Выделить всё

await context.Todos.ToListAsync(cancellationToken);
Я пытаюсь таким образом издеваться, но не получается:

Код: Выделить всё

[Fact]
public async Task Handle_ShouldReturnSuccess_WhenTodoExists()
{
// Arrange
var cancellationToken = new CancellationTokenSource().Token;
List 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);
}
Но он всегда возвращает эту ошибку:

Код: Выделить всё

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()).Returns("hi")
Incorrect use:
sub.MyMethod("hi").Returns(Arg.Any())
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.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
Я пытался написать множество вариантов этого кода, но он не работает. Прежде чем приступить к этому тесту, мне удалось успешно выполнить тест для DeleteTodo (по идентификатору) следующим образом:

Код: Выделить всё

[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);
}
Потому что DeleteTodo было сделано таким образом:

Код: Выделить всё

internal sealed class DeleteTodoCommandHandler(IApplicationDbContext context) : ICommandHandler
{
public async Task Handle(DeleteTodoCommand command, CancellationToken cancellationToken)
{
var entityToRemove = await context.Todos.FindAsync(command.Id, cancellationToken);
if (entityToRemove is null)
{
return Result.Failure(new ResultError("Not found"));
}

context.Todos.Remove(entityToRemove);
var result = await context.SaveChangesAsync(cancellationToken);

return Result.Success(result > 0);
}
}
Есть идеи, что я делаю не так?

Подробнее здесь: https://stackoverflow.com/questions/792 ... r-unittest
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»