From 64332a96a2f723487da9c231fbf154323c3c81b0 Mon Sep 17 00:00:00 2001 From: DmitriyVladarchuk Date: Thu, 18 Sep 2025 14:17:51 +0300 Subject: [PATCH 1/2] test: add unit tests for CategoriesController --- .../Controllers/CategoriesControllerTests.cs | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/FinancialTracker.Tests/Controllers/CategoriesControllerTests.cs b/FinancialTracker.Tests/Controllers/CategoriesControllerTests.cs index ffb2b2b..ee42edd 100644 --- a/FinancialTracker.Tests/Controllers/CategoriesControllerTests.cs +++ b/FinancialTracker.Tests/Controllers/CategoriesControllerTests.cs @@ -52,4 +52,169 @@ public async Task Add_DuplicateCategory_ReturnsConflict() var conflictResult = Assert.IsType(result.Result); Assert.Equal(409, conflictResult.StatusCode); } + + [Fact] + public async Task GetAll_WithCategories_ReturnsOkResult() + { + List categories = + [ + new() { Id = 1, Name = "Продукты"}, + new() { Id = 2, Name = "Транспорт"}, + new() { Id = 3, Name = "Разное"}, + ]; + + _categoryServiceMock + .Setup(service => service.GetAllAsync()) + .ReturnsAsync(categories); + + var result = await _controller.GetAll(); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualCategories = Assert.IsType>(okResult.Value); + Assert.Equal(categories.Count, actualCategories.Count); + Assert.Equal(categories[0].Name, actualCategories[0].Name); + Assert.Equal(categories[1].Name, actualCategories[1].Name); + Assert.Equal(categories[2].Name, actualCategories[2].Name); + } + + [Fact] + public async Task GetAll_EmptyList_ReturnsOkWithEmptyList() + { + var emptyList = new List(); + + _categoryServiceMock + .Setup(service => service.GetAllAsync()) + .ReturnsAsync(emptyList); + + var result = await _controller.GetAll(); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualCategories = Assert.IsType>(okResult.Value); + Assert.Empty(actualCategories); + } + + [Fact] + public async Task GetAll_ServiceThrowsException_ReturnsServerError() + { + const string errorMessage = "Внутренняя ошибка сервера при получении категорий"; + + _categoryServiceMock + .Setup(service => service.GetAllAsync()) + .ThrowsAsync(new Exception(errorMessage)); + + var result = await _controller.GetAll(); + + var statusCodeResult = Assert.IsType(result.Result); + Assert.Equal(500, statusCodeResult.StatusCode); + } + + [Fact] + public async Task GetById_ExistingCategory_ReturnsOk() + { + var categoryId = 1; + var expectedCategory = new CategoryResponseDto { Id = categoryId, Name = "Продукты" }; + + _categoryServiceMock + .Setup(service => service.GetByIdAsync(categoryId)) + .ReturnsAsync(expectedCategory); + + var result = await _controller.GetById(categoryId); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualCategory = Assert.IsType(okResult.Value); + Assert.Equal(expectedCategory.Id, actualCategory.Id); + Assert.Equal(expectedCategory.Name, actualCategory.Name); + } + + [Fact] + public async Task GetById_NonExistingCategory_ReturnsNotFound() + { + const int categoryId = 999; + + _categoryServiceMock + .Setup(service => service.GetByIdAsync(categoryId)) + .ReturnsAsync((CategoryResponseDto)null!); + + var result = await _controller.GetById(categoryId); + + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal(404, notFoundResult.StatusCode); + } + + [Fact] + public async Task Update_ValidCategory_ReturnsOk() + { + var updateDto = new CategoryUpdateDto { Id = 1, Name = "Продукты обновленные" }; + var expectedCategory = new CategoryResponseDto { Id = 1, Name = "Продукты обновленные" }; + + _categoryServiceMock + .Setup(service => service.UpdateAsync(updateDto)) + .ReturnsAsync(expectedCategory); + + var result = await _controller.Update(updateDto); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualCategory = Assert.IsType(okResult.Value); + Assert.Equal(expectedCategory.Id, actualCategory.Id); + Assert.Equal(expectedCategory.Name, actualCategory.Name); + } + + [Fact] + public async Task Update_DuplicateCategoryName_ReturnsConflict() + { + var updateDto = new CategoryUpdateDto { Id = 1, Name = "Дубликат" }; + const string errorMessage = "Попытка обновления категории на дублирующее имя: 1 -> Дубликат"; + + _categoryServiceMock + .Setup(service => service.UpdateAsync(updateDto)) + .ThrowsAsync(new InvalidOperationException(errorMessage)); + + var result = await _controller.Update(updateDto); + + var conflictResult = Assert.IsType(result.Result); + Assert.Equal(409, conflictResult.StatusCode); + } + + [Fact] + public async Task Delete_ExistingCategory_ReturnsOk() + { + const int categoryId = 1; + var expectedCategory = new CategoryResponseDto { Id = categoryId, Name = "Продукты" }; + + _categoryServiceMock + .Setup(service => service.DeleteAsync(categoryId)) + .ReturnsAsync(expectedCategory); + + var result = await _controller.Delete(categoryId); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualCategory = Assert.IsType(okResult.Value); + Assert.Equal(expectedCategory.Id, actualCategory.Id); + Assert.Equal(expectedCategory.Name, actualCategory.Name); + } + + [Fact] + public async Task Delete_NonExistingCategory_ReturnsNotFound() + { + const int categoryId = 999; + + _categoryServiceMock + .Setup(service => service.DeleteAsync(categoryId)) + .ReturnsAsync((CategoryResponseDto)null!); + + var result = await _controller.Delete(categoryId); + + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal(404, notFoundResult.StatusCode); + } } \ No newline at end of file From d15c90cc792ede610a4b157aeb1a07df2789eb39 Mon Sep 17 00:00:00 2001 From: DmitriyVladarchuk Date: Thu, 18 Sep 2025 14:41:30 +0300 Subject: [PATCH 2/2] test: add unit tests for TransactionsController --- .../TransactionsControllerTests.cs | 294 ++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 FinancialTracker.Tests/Controllers/TransactionsControllerTests.cs diff --git a/FinancialTracker.Tests/Controllers/TransactionsControllerTests.cs b/FinancialTracker.Tests/Controllers/TransactionsControllerTests.cs new file mode 100644 index 0000000..68b3094 --- /dev/null +++ b/FinancialTracker.Tests/Controllers/TransactionsControllerTests.cs @@ -0,0 +1,294 @@ +using FinancialTracker.Controllers; +using FinancialTracker.DTOs.TransactionDtos; +using FinancialTracker.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Moq; + +namespace FinancialTracker.Tests.Controllers; + +public class TransactionsControllerTests +{ + private readonly Mock _transactionServiceMock; + private readonly Mock> _loggerMock; + private readonly TransactionsController _controller; + + public TransactionsControllerTests() + { + _transactionServiceMock = new Mock(); + _loggerMock = new Mock>(); + _controller = new TransactionsController(_transactionServiceMock.Object, _loggerMock.Object); + } + + [Fact] + public async Task Add_ValidTransaction_ReturnsCreatedResult() + { + var createDto = new TransactionCreateDto + { + Amount = 1000, + Description = "Покупка продуктов", + CategoryId = 1, + }; + + var expectedTransaction = new TransactionResponseDto + { + Id = 1, + Amount = 1000, + Description = "Покупка продуктов", + Date = DateTime.Now, + CategoryName = "Продукты" + }; + + _transactionServiceMock + .Setup(service => service.AddAsync(createDto)) + .ReturnsAsync(expectedTransaction); + + var result = await _controller.Add(createDto); + + var createdAtResult = Assert.IsType(result.Result); + Assert.Equal(201, createdAtResult.StatusCode); + Assert.Equal(expectedTransaction, createdAtResult.Value); + } + + [Fact] + public async Task Add_ServiceThrowsException_ReturnsServerError() + { + var createDto = new TransactionCreateDto + { + Amount = 1000, + Description = "Покупка продуктов", + CategoryId = 1 + }; + + _transactionServiceMock + .Setup(service => service.AddAsync(createDto)) + .ThrowsAsync(new Exception("Database error")); + + var result = await _controller.Add(createDto); + + var statusCodeResult = Assert.IsType(result.Result); + Assert.Equal(500, statusCodeResult.StatusCode); + } + + [Fact] + public async Task GetAll_WithTransactions_ReturnsOk() + { + var expectedTransactions = new List + { + new() + { + Id = 1, + Amount = 1000, + Description = "Продукты", + CategoryName = "Еда", + CategoryId = 1, + }, + new() + { + Id = 2, + Amount = 500, + Description = "Транспорт", + CategoryName = "Транспорт", + CategoryId = 2, + } + }; + + _transactionServiceMock + .Setup(service => service.GetAllAsync()) + .ReturnsAsync(expectedTransactions); + + var result = await _controller.GetAll(); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualTransactions = Assert.IsType>(okResult.Value); + Assert.Equal(expectedTransactions.Count, actualTransactions.Count); + Assert.Equal(expectedTransactions[0].Id, actualTransactions[0].Id); + Assert.Equal(expectedTransactions[0].Amount, actualTransactions[0].Amount); + Assert.Equal(expectedTransactions[0].Description, actualTransactions[0].Description); + Assert.Equal(expectedTransactions[0].CategoryName, actualTransactions[0].CategoryName); + Assert.Equal(expectedTransactions[0].Date, actualTransactions[0].Date); + Assert.Equal(expectedTransactions[0].CategoryId, actualTransactions[0].CategoryId); + } + + [Fact] + public async Task GetAll_EmptyList_ReturnsOkWithEmptyList() + { + var emptyList = new List(); + + _transactionServiceMock + .Setup(service => service.GetAllAsync()) + .ReturnsAsync(emptyList); + + var result = await _controller.GetAll(); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + } + + [Fact] + public async Task GetAll_ServiceThrowsException_ReturnsInternalServerError() + { + _transactionServiceMock + .Setup(service => service.GetAllAsync()) + .ThrowsAsync(new Exception("Database error")); + + var result = await _controller.GetAll(); + + var statusCodeResult = Assert.IsType(result.Result); + Assert.Equal(500, statusCodeResult.StatusCode); + } + + [Fact] + public async Task GetById_ExistingTransaction_ReturnsOkWithTransaction() + { + const int transactionId = 1; + var expectedTransaction = new TransactionResponseDto + { + Id = transactionId, + Amount = 1000, + Description = "Продукты", + CategoryName = "Еда", + CategoryId = 1, + }; + + _transactionServiceMock + .Setup(service => service.GetByIdAsync(transactionId)) + .ReturnsAsync(expectedTransaction); + + var result = await _controller.GetById(transactionId); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualTransaction = Assert.IsType(okResult.Value); + Assert.Equal(expectedTransaction.Id, actualTransaction.Id); + Assert.Equal(expectedTransaction.Amount, actualTransaction.Amount); + Assert.Equal(expectedTransaction.Description, actualTransaction.Description); + Assert.Equal(expectedTransaction.CategoryName, actualTransaction.CategoryName); + Assert.Equal(expectedTransaction.Date, actualTransaction.Date); + Assert.Equal(expectedTransaction.CategoryId, actualTransaction.CategoryId); + } + + [Fact] + public async Task GetById_NonExistingTransaction_ReturnsNotFound() + { + const int transactionId = 999; + + _transactionServiceMock + .Setup(service => service.GetByIdAsync(transactionId)) + .ReturnsAsync((TransactionResponseDto)null!); + + var result = await _controller.GetById(transactionId); + + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal(404, notFoundResult.StatusCode); + } + + [Fact] + public async Task Update_ExistingTransaction_ReturnsOk() + { + var updateDto = new TransactionUpdateDto + { + Id = 1, + Amount = 1500, + Description = "Продукты обновленные", + CategoryId = 2 + }; + + var expectedTransaction = new TransactionResponseDto + { + Id = 1, + Amount = 1500, + Description = "Продукты обновленные", + CategoryName = "Супермаркет", + CategoryId = 2, + Date = DateTime.Now + }; + + _transactionServiceMock + .Setup(service => service.UpdateAsync(updateDto)) + .ReturnsAsync(expectedTransaction); + + var result = await _controller.Update(updateDto); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualTransaction = Assert.IsType(okResult.Value); + Assert.Equal(expectedTransaction.Id, actualTransaction.Id); + Assert.Equal(expectedTransaction.Amount, actualTransaction.Amount); + Assert.Equal(expectedTransaction.Description, actualTransaction.Description); + Assert.Equal(expectedTransaction.CategoryName, actualTransaction.CategoryName); + Assert.Equal(expectedTransaction.Date, actualTransaction.Date); + Assert.Equal(expectedTransaction.CategoryId, actualTransaction.CategoryId); + } + + [Fact] + public async Task Update_NonExistingTransaction_ReturnsNotFound() + { + var updateDto = new TransactionUpdateDto + { + Id = 999, + Amount = 1500, + Description = "Несуществующая транзакция", + CategoryId = 1 + }; + + _transactionServiceMock + .Setup(service => service.UpdateAsync(updateDto)) + .ReturnsAsync((TransactionResponseDto)null!); + + var result = await _controller.Update(updateDto); + + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal(404, notFoundResult.StatusCode); + } + + [Fact] + public async Task Delete_ExistingTransaction_ReturnsOkWithDeletedTransaction() + { + const int transactionId = 1; + var expectedTransaction = new TransactionResponseDto + { + Id = transactionId, + Amount = 1000, + Description = "Продукты", + CategoryName = "Еда", + CategoryId = 1, + }; + + _transactionServiceMock + .Setup(service => service.DeleteAsync(transactionId)) + .ReturnsAsync(expectedTransaction); + + var result = await _controller.Delete(transactionId); + + var okResult = Assert.IsType(result.Result); + Assert.Equal(200, okResult.StatusCode); + + var actualTransaction = Assert.IsType(okResult.Value); + Assert.Equal(expectedTransaction.Id, actualTransaction.Id); + Assert.Equal(expectedTransaction.Amount, actualTransaction.Amount); + Assert.Equal(expectedTransaction.Description, actualTransaction.Description); + Assert.Equal(expectedTransaction.CategoryName, actualTransaction.CategoryName); + Assert.Equal(expectedTransaction.Date, actualTransaction.Date); + Assert.Equal(expectedTransaction.CategoryId, actualTransaction.CategoryId); + } + + [Fact] + public async Task Delete_NonExistingTransaction_ReturnsNotFound() + { + const int transactionId = 999; + + _transactionServiceMock + .Setup(service => service.DeleteAsync(transactionId)) + .ReturnsAsync((TransactionResponseDto)null!); + + var result = await _controller.Delete(transactionId); + + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal(404, notFoundResult.StatusCode); + } +} \ No newline at end of file