20
loading...
This website collects cookies to deliver better user experience
UpdateTodoListCommandHandler
and assume it is a real-world project and we some logic inside the Handle
method but we don't implement integration for each scenario. Here is the actual implementation of :namespace CleanArchitecture.Application.TodoLists.Commands.UpdateTodoList
{
public class UpdateTodoListCommand : IRequest
{
public int Id { get; set; }
public string Title { get; set; }
}
public class UpdateTodoListCommandHandler : IRequestHandler<UpdateTodoListCommand>
{
private readonly IApplicationDbContext _context;
public UpdateTodoListCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<Unit> Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoLists.FindAsync(request.Id);
if (entity == null)
{
throw new NotFoundException(nameof(TodoList), request.Id);
}
entity.Title = request.Title;
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}
}
}
NotFoundException
is thrown.[Test]
public void Update_TodoList_Throws_Exception_When_Entity_Does_Not_Exist()
{
// Arrange
var list = new List<TodoList>();
var queryable = list.AsQueryable();
var dbSet = new Mock<DbSet<TodoList>>();
dbSet.As<IQueryable<TodoList>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<TodoList>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.FindAsync(It.IsAny<object[]>())).ReturnsAsync((object[] id) => list.SingleOrDefault(t => t.Id == (int)id[0]));
var dbContext = new Mock<IApplicationDbContext>();
dbContext.SetupGet(d => d.TodoLists).Returns(dbSet.Object);
var sut = new UpdateTodoListCommandHandler(dbContext.Object);
var command = new UpdateTodoListCommand { Id = 1, Title = "Test" };
// Act
var exception = Assert.ThrowsAsync<NotFoundException>(() => sut.Handle(command, new CancellationToken()));
// Assert
Assert.NotNull(exception);
}
IApplicationDbContext
and the interface should help to hide underlying implementation but to implement such a test you should know how to mock DbSet
. If you use the ApplicationDbContext
class instead of IApplicationDbContext
interface, the result will be the same and same amount of code is need to mock ApplicationDbContext
class.IApplicationDbContext
with ITodoListRepository
.public interface ITodoListRepository
{
Task<TodoList> GetByIdAsync(int id);
Task UpdateAsync(TodoList todoList);
}
public class UpdateTodoListCommandHandler : IRequestHandler<UpdateTodoListCommand>
{
private readonly ITodoListRepository _repository;
public UpdateTodoListCommandHandler(ITodoListRepository repository)
{
_repository = repository;
}
public async Task<Unit> Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _repository.GetByIdAsync(request.Id);
if (entity == null)
{
throw new NotFoundException(nameof(TodoList), request.Id);
}
entity.Title = request.Title;
await _repository.UpdateAsync(entity);
return Unit.Value;
}
}
[Test]
public void Test1()
{
// Arrange
var list = new List<TodoList>();
var repository = new Mock<ITodoListRepository>();
repository.Setup(r => r.GetByIdAsync(It.IsAny<int>())).ReturnsAsync((int id) => list.SingleOrDefault(t => t.Id == id));
var command = new UpdateTodoListCommand { Title = "Test", Id = 1 };
var sut = new UpdateTodoListCommandHandler(repository.Object);
// Act
var exception = Assert.ThrowsAsync<NotFoundException>(async () => await sut.Handle(command, new CancellationToken()));
// Act
Assert.NotNull(exception);
Assert.AreEqual(typeof(NotFoundException), exception.GetType());
}