Skip to content

Commit

Permalink
feat(unittests): added all the remaining tests for Expenses and pendi…
Browse files Browse the repository at this point in the history
…ng GetAllCategoriesQuery tests; used MockQueryable.Moq library to handle IAsyncQueriableProvider implementation
  • Loading branch information
mezdelex committed Nov 12, 2024
1 parent 478f068 commit 38d0e2b
Show file tree
Hide file tree
Showing 11 changed files with 368 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public async Task DeleteCategoryCommandHandler_ShouldDeleteCategory()
await _handler.Handle(deleteCategoryCommand, _cancellationToken);

// Assert
_repository.Verify();
_uow.Verify();
_repository.Verify(
mock => mock.DeleteAsync(It.IsAny<Guid>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace Application.UnitTests.Expenses.PostAsync;

public sealed class DeleteExpenseCommandHandlerTests
{
private readonly CancellationToken _cancellationToken;
private readonly Mock<IExpensesRepository> _repository;
private readonly Mock<IUnitOfWork> _uow;
private readonly DeleteExpenseCommandHandler _handler;

public DeleteExpenseCommandHandlerTests()
{
_cancellationToken = new();
_repository = new();
_uow = new();

_handler = new DeleteExpenseCommandHandler(_repository.Object, _uow.Object);
}

[Fact]
public async Task DeleteExpenseCommandHandler_ShouldDeleteExpense()
{
// Arrange
var deleteExpenseCommand = new DeleteExpenseCommand(Guid.NewGuid());
_repository
.Setup(mock => mock.DeleteAsync(It.IsAny<Guid>(), _cancellationToken))
.Verifiable();
_uow.Setup(mock => mock.SaveChangesAsync(_cancellationToken)).Verifiable();

// Act
await _handler.Handle(deleteExpenseCommand, _cancellationToken);

// Assert
_repository.Verify(
mock => mock.DeleteAsync(It.IsAny<Guid>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public async Task PatchCategoryCommandHandler_ShouldPatchCategoryAndPublishEvent
"Category 1 description"
);
_validator
.Setup(mock => mock.ValidateAsync(patchCategoryCommand, _cancellationToken))
.Setup(mock => mock.ValidateAsync(It.IsAny<PatchCategoryCommand>(), _cancellationToken))
.ReturnsAsync(new ValidationResult())
.Verifiable();
_repository
Expand All @@ -50,9 +50,18 @@ public async Task PatchCategoryCommandHandler_ShouldPatchCategoryAndPublishEvent
await _handler.Handle(patchCategoryCommand, _cancellationToken);

// Assert
_validator.Verify();
_repository.Verify();
_uow.Verify();
_eventBus.Verify();
_validator.Verify(
mock => mock.ValidateAsync(It.IsAny<PatchCategoryCommand>(), _cancellationToken),
Times.Once
);
_repository.Verify(
mock => mock.PatchAsync(It.IsAny<Category>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
_eventBus.Verify(
mock => mock.PublishAsync(It.IsAny<PatchedCategoryEvent>(), _cancellationToken),
Times.Once
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace Application.UnitTests.Expenses.PostAsync;

public sealed class PatchExpenseCommandHandlerTests
{
private readonly CancellationToken _cancellationToken;
private readonly Mock<IValidator<PatchExpenseCommand>> _validator;
private readonly Mock<IExpensesRepository> _repository;
private readonly Mock<IUnitOfWork> _uow;
private readonly Mock<IEventBus> _eventBus;
private readonly PatchExpenseCommandHandler _handler;

public PatchExpenseCommandHandlerTests()
{
_cancellationToken = new();
_validator = new();
_repository = new();
_uow = new();
_eventBus = new();

_handler = new PatchExpenseCommandHandler(
_validator.Object,
_repository.Object,
_uow.Object,
_eventBus.Object
);
}

[Fact]
public async Task PatchExpenseCommandHandler_ShouldPatchExpenseAndPublishEventAsync()
{
// Arrange
var patchExpenseCommand = new PatchExpenseCommand(
Guid.NewGuid(),
"Expense 1 name",
"Expense 1 description",
1,
new Guid()
);
_validator
.Setup(mock => mock.ValidateAsync(It.IsAny<PatchExpenseCommand>(), _cancellationToken))
.ReturnsAsync(new ValidationResult())
.Verifiable();
_repository
.Setup(mock => mock.PatchAsync(It.IsAny<Expense>(), _cancellationToken))
.Verifiable();
_uow.Setup(mock => mock.SaveChangesAsync(_cancellationToken)).Verifiable();
_eventBus
.Setup(mock => mock.PublishAsync(It.IsAny<PatchedExpenseEvent>(), _cancellationToken))
.Verifiable();

// Act
await _handler.Handle(patchExpenseCommand, _cancellationToken);

// Assert
_validator.Verify(
mock => mock.ValidateAsync(It.IsAny<PatchExpenseCommand>(), _cancellationToken),
Times.Once
);
_repository.Verify(
mock => mock.PatchAsync(It.IsAny<Expense>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
_eventBus.Verify(
mock => mock.PublishAsync(It.IsAny<PatchedExpenseEvent>(), _cancellationToken),
Times.Once
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,18 @@ public async Task PostCategoryCommandHandler_ShouldPostCategoryAndPublishEventAs
await _handler.Handle(postCategoryCommand, _cancellationToken);

// Assert
_validator.Verify();
_repository.Verify();
_uow.Verify();
_eventBus.Verify();
_validator.Verify(
mock => mock.ValidateAsync(It.IsAny<PostCategoryCommand>(), _cancellationToken),
Times.Once
);
_repository.Verify(
mock => mock.PostAsync(It.IsAny<Category>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
_eventBus.Verify(
mock => mock.PublishAsync(It.IsAny<PostedCategoryEvent>(), _cancellationToken),
Times.Once
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
namespace Application.UnitTests.Expenses.PostAsync;

public sealed class PostExpenseCommandHandlerTests
{
private readonly CancellationToken _cancellationToken;
private readonly Mock<IValidator<PostExpenseCommand>> _validator;
private readonly Mock<IExpensesRepository> _repository;
private readonly Mock<IUnitOfWork> _uow;
private readonly Mock<IEventBus> _eventBus;
private readonly PostExpenseCommandHandler _handler;

public PostExpenseCommandHandlerTests()
{
_cancellationToken = new();
_validator = new();
_repository = new();
_uow = new();
_eventBus = new();

_handler = new PostExpenseCommandHandler(
_validator.Object,
_repository.Object,
_uow.Object,
_eventBus.Object
);
}

[Fact]
public async Task PostExpenseCommandHandler_ShouldPostExpenseAndPublishEventAsync()
{
// Arrange
var postExpenseCommand = new PostExpenseCommand(
"Expense 1 name",
"Expense 1 description",
1,
new Guid()
);
_validator
.Setup(mock => mock.ValidateAsync(postExpenseCommand, _cancellationToken))
.ReturnsAsync(new ValidationResult())
.Verifiable();
_repository
.Setup(mock => mock.PostAsync(It.IsAny<Expense>(), _cancellationToken))
.Verifiable();
_uow.Setup(mock => mock.SaveChangesAsync(_cancellationToken)).Verifiable();
_eventBus
.Setup(mock => mock.PublishAsync(It.IsAny<PostedExpenseEvent>(), _cancellationToken))
.Verifiable();

// Act
await _handler.Handle(postExpenseCommand, _cancellationToken);

// Assert
_validator.Verify(
mock => mock.ValidateAsync(It.IsAny<PostExpenseCommand>(), _cancellationToken),
Times.Once
);
_repository.Verify(
mock => mock.PostAsync(It.IsAny<Expense>(), _cancellationToken),
Times.Once
);
_uow.Verify(mock => mock.SaveChangesAsync(_cancellationToken), Times.Once);
_eventBus.Verify(
mock => mock.PublishAsync(It.IsAny<PostedExpenseEvent>(), _cancellationToken),
Times.Once
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,17 @@ public GetAllCategoriesQueryHandlerTests()
_handler = new GetAllCategoriesQueryHandler(_repository.Object, _redisCache.Object);
}

[Fact(Skip = "Pending IAsyncQueryProvider mock implementation")]
[Fact]
public async Task GetAllCategoriesQueryHandler_ShouldReturnPagedListOfRequestedCategoriesAsListOfCategoryDTOAndMetadata()
{
// Arrange
var name = "Test";
var containedWord = "es";
var containedWord = "am";
var page = 1;
var pageSize = 2;
var getAllCategoriesQuery = new GetAllCategoriesQuery
{
Page = page,
PageSize = pageSize,
Name = name,
ContainedWord = containedWord,
};
var redisKey = $"{nameof(GetAllCategoriesQuery)}#{page}#{pageSize}";
Expand All @@ -47,17 +45,10 @@ public async Task GetAllCategoriesQueryHandler_ShouldReturnPagedListOfRequestedC
Description = "Description 2",
},
};
var pagedCategories = new PagedList<Category>(
categories,
page,
pageSize,
categories.Count,
false,
false
);
_repository
.Setup(mock => mock.ApplySpecification(It.IsAny<CategoriesSpecification>()))
.Returns(categories.AsQueryable);
.Returns(categories.BuildMock())
.Verifiable();
_redisCache
.Setup(mock => mock.GetCachedData<PagedList<CategoryDTO>>(redisKey))
.ReturnsAsync((PagedList<CategoryDTO>)null!);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
namespace UnitTests.Features.Queries;

public sealed class GetAllExpensesQueryHandlerTests
{
private readonly CancellationToken _cancellationToken;
private readonly Mock<IExpensesRepository> _repository;
private readonly Mock<IRedisCache> _redisCache;
private readonly GetAllExpensesQueryHandler _handler;

public GetAllExpensesQueryHandlerTests()
{
_cancellationToken = new();
_repository = new();
_redisCache = new();

_handler = new GetAllExpensesQueryHandler(_repository.Object, _redisCache.Object);
}

[Fact]
public async Task GetAllExpensesQueryHandler_ShouldReturnPagedListOfRequestedExpensesAsListOfExpenseDTOAndMetadata()
{
// Arrange
var containedWord = "am";
var page = 1;
var pageSize = 2;
var getAllExpensesQuery = new GetAllExpensesQuery
{
Page = page,
PageSize = pageSize,
ContainedWord = containedWord,
};
var redisKey = $"{nameof(GetAllExpensesQuery)}#{page}#{pageSize}";
var expenses = new List<Expense>
{
new()
{
Id = Guid.NewGuid(),
Name = "Name 1",
Description = "Description 1",
Value = 1,
},
new()
{
Id = Guid.NewGuid(),
Name = "Name 2",
Description = "Description 2",
Value = 2,
},
};
_repository
.Setup(mock => mock.ApplySpecification(It.IsAny<ExpensesSpecification>()))
.Returns(expenses.BuildMock())
.Verifiable();
_redisCache
.Setup(mock => mock.GetCachedData<PagedList<ExpenseDTO>>(redisKey))
.ReturnsAsync((PagedList<ExpenseDTO>)null!);
_redisCache
.Setup(mock =>
mock.SetCachedData(
redisKey,
It.IsAny<PagedList<ExpenseDTO>>(),
It.IsAny<DateTimeOffset>()
)
)
.Returns(Task.CompletedTask)
.Verifiable();

// Act
var result = await _handler.Handle(getAllExpensesQuery, _cancellationToken);

// Assert
result.Items[0].Id.Should().Be(expenses[0].Id);
result.Items[0].Name.Should().Be(expenses[0].Name);
result.Items[0].Description.Should().Be(expenses[0].Description);
result.Items[0].Value.Should().Be(expenses[0].Value);
result.Items[1].Id.Should().Be(expenses[1].Id);
result.Items[1].Name.Should().Be(expenses[1].Name);
result.Items[1].Value.Should().Be(expenses[1].Value);
result.TotalCount.Should().Be(expenses.Count);
result.Page.Should().Be(page);
result.PageSize.Should().Be(pageSize);
result.HasPreviousPage.Should().Be(false);
result.HasNextPage.Should().Be(false);
_repository.Verify(
mock => mock.ApplySpecification(It.IsAny<ExpensesSpecification>()),
Times.Once
);
_redisCache.Verify(mock => mock.GetCachedData<PagedList<ExpenseDTO>>(redisKey), Times.Once);
_redisCache.Verify(
mock =>
mock.SetCachedData(
redisKey,
It.IsAny<PagedList<ExpenseDTO>>(),
It.IsAny<DateTimeOffset>()
),
Times.Once
);
}
}
Loading

0 comments on commit 38d0e2b

Please sign in to comment.