From 92c66e5d5a4e96a4e9cd7164535a3b295ae7ba71 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 9 Dec 2024 19:27:02 +0400 Subject: [PATCH] =?UTF-8?q?add:=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=81=D0=B5=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D1=8B=20=D0=B0=D0=BF=D0=B8=20=D0=B8=20=D0=B8=D1=85=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Api.sln | 6 + .../Services.Tests/Domain/AuthServiceTests.cs | 83 +++++++++++ .../Domain/ChangeRecordServiceTests.cs | 138 ++++++++++++++++++ .../Domain/SpendingGroupServiceTests.cs | 118 +++++++++++++++ .../Domain/SpendingPlanServiceTests.cs | 101 +++++++++++++ .../Services.Tests/Domain/UserServiceTests.cs | 74 ++++++++++ back/Services.Tests/Services.Tests.csproj | 28 ++++ .../Support/Fakes/Database/DbFake.cs | 13 ++ .../Fakes/Repositories/UserRepoFake.cs | 55 +++++++ back/Services/Domain/ChangeRecordService.cs | 5 +- 10 files changed, 619 insertions(+), 2 deletions(-) create mode 100644 back/Services.Tests/Domain/AuthServiceTests.cs create mode 100644 back/Services.Tests/Domain/ChangeRecordServiceTests.cs create mode 100644 back/Services.Tests/Domain/SpendingGroupServiceTests.cs create mode 100644 back/Services.Tests/Domain/SpendingPlanServiceTests.cs create mode 100644 back/Services.Tests/Domain/UserServiceTests.cs create mode 100644 back/Services.Tests/Services.Tests.csproj create mode 100644 back/Services.Tests/Support/Fakes/Database/DbFake.cs create mode 100644 back/Services.Tests/Support/Fakes/Repositories/UserRepoFake.cs diff --git a/back/Api.sln b/back/Api.sln index c0cdbbb..15b921a 100644 --- a/back/Api.sln +++ b/back/Api.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "Contracts\Cont EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{A35121D4-7D41-4266-8DA4-87135E8ABF89}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services.Tests", "Services.Tests\Services.Tests.csproj", "{F0BDEEB0-2850-4733-B196-DBC677B35E47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,5 +38,9 @@ Global {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Debug|Any CPU.Build.0 = Debug|Any CPU {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.ActiveCfg = Release|Any CPU {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.Build.0 = Release|Any CPU + {F0BDEEB0-2850-4733-B196-DBC677B35E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0BDEEB0-2850-4733-B196-DBC677B35E47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0BDEEB0-2850-4733-B196-DBC677B35E47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0BDEEB0-2850-4733-B196-DBC677B35E47}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/back/Services.Tests/Domain/AuthServiceTests.cs b/back/Services.Tests/Domain/AuthServiceTests.cs new file mode 100644 index 0000000..1b1ffb1 --- /dev/null +++ b/back/Services.Tests/Domain/AuthServiceTests.cs @@ -0,0 +1,83 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.ViewModels; +using Moq; +using Services.Domain; +using Services.Support.Exceptions; + +namespace Services.Tests.Domain; + +public class AuthServiceTests +{ + [Fact] + public void Register_WhenUserExists_ThrowsAlreadyExistsException() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())) + .ReturnsAsync(new UserDto()); + var authService = new AuthService(userRepoMock.Object); + var user = new UserDto { Name = "John Doe", Password = "password" }; + + Assert.ThrowsAsync(() => authService.Register(user)); + } + + [Fact] + public void Register_WhenUserDoesNotExist_ThenCreateUser_ReturnsUserViewModel() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync((UserDto)null); + userRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new UserDto()); + var authService = new AuthService(userRepoMock.Object); + var user = new UserDto { Name = "John Doe", Password = "password" }; + + var result = authService.Register(user); + + userRepoMock.Verify(repo => repo.Create(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType>(result); + } + + [Fact] + public void Login_WhenUserDoesNotExist_ThrowsUserNotFoundException() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync((UserDto)null); + var authService = new AuthService(userRepoMock.Object); + var user = new UserLoginDto { Name = "John Doe", Password = "password" }; + + Assert.ThrowsAsync(() => authService.Login(user)); + } + + [Fact] + public void Login_WhenUserExists_ReturnsUserViewModel() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync(new UserDto()); + var authService = new AuthService(userRepoMock.Object); + var user = new UserLoginDto { Name = "John Doe", Password = "password" }; + + var result = authService.Login(user); + + userRepoMock.Verify(repo => repo.Get(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType>(result); + } + + [Fact] + public void Login_WhenWrongLoginData_ThrowsArgumentException() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync((UserDto)null); + var authService = new AuthService(userRepoMock.Object); + UserLoginDto user1 = null; + UserLoginDto user2 = new() { Name = "", Password = "password" }; + UserLoginDto user3 = new() { Name = "John Doe", Password = "" }; + UserLoginDto user4 = new() { Name = "", Password = "" }; + + Assert.ThrowsAsync(() => authService.Login(user1)); + Assert.ThrowsAsync(() => authService.Login(user2)); + Assert.ThrowsAsync(() => authService.Login(user3)); + Assert.ThrowsAsync(() => authService.Login(user4)); + } +} \ No newline at end of file diff --git a/back/Services.Tests/Domain/ChangeRecordServiceTests.cs b/back/Services.Tests/Domain/ChangeRecordServiceTests.cs new file mode 100644 index 0000000..53427f9 --- /dev/null +++ b/back/Services.Tests/Domain/ChangeRecordServiceTests.cs @@ -0,0 +1,138 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.ViewModels; +using Moq; +using Services.Domain; +using Services.Support.Exceptions; +using Services.Tests.Support.Fakes.Database; +using Services.Tests.Support.Fakes.Repositories; + +namespace Services.Tests.Domain; + +public class ChangeRecordServiceTests +{ + [Theory] + [InlineData(50)] + [InlineData(-50)] + public async Task Create_WhenUserExists_ThenChangeBalance_ReturnsChangeRecordViewModel(int recordSum, int userBalance = 100) + { + var userRepoFake = new UserRepoFake(); + var changeRecordRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new ChangeRecordDto()); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoFake); + // Add user + var user = new UserDto() { Id = Guid.NewGuid(), Balance = userBalance }; + await userRepoFake.Create(user); + var changeRecord = new ChangeRecordDto { UserId = user.Id, Sum = recordSum, SpendingGroupId = Guid.NewGuid() }; + + var result = await changeRecordService.Create(changeRecord); + + changeRecordRepoMock.Verify(repo => repo.Create(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + var existedUser = await userRepoFake.Get(new UserSearch { Id = user.Id }); + Assert.Equal(existedUser.Balance, userBalance + recordSum); + + DbFake.ClearDb(); + } + + [Theory] + [InlineData(50)] + [InlineData(-50)] + public async Task Delete_WhenUserExists_ThenChangeBalance_ReturnsChangeRecordViewModel(int recordSum, int userBalance = 100) + { + var user = new UserDto() { Id = Guid.NewGuid(), Balance = userBalance }; + var changeRecord = new ChangeRecordDto { UserId = user.Id, Sum = recordSum, SpendingGroupId = Guid.NewGuid() }; + var userRepoFake = new UserRepoFake(); + var changeRecordRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync(changeRecord); + changeRecordRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new ChangeRecordDto()); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoFake); + // Add user and record + await userRepoFake.Create(user); + await changeRecordService.Create(changeRecord); + + var result = await changeRecordService.Delete(new ChangeRecordSearch { Id = changeRecord.Id }); + + changeRecordRepoMock.Verify(repo => repo.Delete(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + var existedUser = await userRepoFake.Get(new UserSearch { Id = user.Id }); + Assert.Equal(existedUser.Balance, userBalance); + + DbFake.ClearDb(); + } + + [Fact] + public void Delete_WhenRecordNotFound_ThenThrowsEntityNotFoundException() + { + var changeRecordRepoMock = new Mock(); + var userRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync((ChangeRecordDto)null); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoMock.Object); + + Assert.ThrowsAsync(() => changeRecordService.Delete(new())); + } + + [Fact] + public async Task GetList_ReturnsChangeRecordViewModels() + { + var changeRecordRepoMock = new Mock(); + var userRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.GetList(It.IsAny())).ReturnsAsync(GetAllChangeRecords()); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoMock.Object); + + var result = await changeRecordService.GetList(); + + changeRecordRepoMock.Verify(repo => repo.GetList(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType>(result.ToList()); + } + + [Theory] + [InlineData(50, 25)] + [InlineData(-50, 25)] + public async Task Update_WhenUserExists_ThenChangeBalance_ReturnsChangeRecordViewModel(int recordSum, int recorNewSum, int userBalance = 100) + { + var user = new UserDto() { Id = Guid.NewGuid(), Balance = userBalance }; + var changeRecord = new ChangeRecordDto { UserId = user.Id, Sum = recordSum, SpendingGroupId = Guid.NewGuid() }; + var userRepoFake = new UserRepoFake(); + var changeRecordRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync(changeRecord); + changeRecordRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new ChangeRecordDto()); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoFake); + // Add user and record + await userRepoFake.Create(user); + await changeRecordService.Create(changeRecord); + var newChangeRecord = new ChangeRecordDto { Id = Guid.NewGuid(), UserId = user.Id, Sum = recorNewSum, SpendingGroupId = Guid.NewGuid() }; + + var result = await changeRecordService.Update(newChangeRecord); + + changeRecordRepoMock.Verify(repo => repo.Update(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + var existedUser = await userRepoFake.Get(new UserSearch { Id = user.Id }); + Assert.Equal(existedUser.Balance, userBalance + recorNewSum); + + DbFake.ClearDb(); + } + + [Fact] + public void Update_WhenRecordNotExists_ThenThrowsEntityNotFoundException() + { + var changeRecordRepoMock = new Mock(); + changeRecordRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync((ChangeRecordDto?)null); + var userRepoMock = new Mock(); + var changeRecordService = new ChangeRecordService(changeRecordRepoMock.Object, userRepoMock.Object); + var changeRecord = new ChangeRecordDto { Id = Guid.NewGuid(), UserId = Guid.NewGuid(), Sum = 50, SpendingGroupId = Guid.NewGuid() }; + + Assert.ThrowsAsync(() => changeRecordService.Update(changeRecord)); + } + + public IEnumerable GetAllChangeRecords() => new List() + { + new ChangeRecordDto() { Id = Guid.NewGuid(), Sum = 50, SpendingGroupId = Guid.NewGuid(), UserId = Guid.NewGuid() }, + new ChangeRecordDto() { Id = Guid.NewGuid(), Sum = 50, SpendingGroupId = Guid.NewGuid(), UserId = Guid.NewGuid() }, + }; +} \ No newline at end of file diff --git a/back/Services.Tests/Domain/SpendingGroupServiceTests.cs b/back/Services.Tests/Domain/SpendingGroupServiceTests.cs new file mode 100644 index 0000000..a1eaf16 --- /dev/null +++ b/back/Services.Tests/Domain/SpendingGroupServiceTests.cs @@ -0,0 +1,118 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Moq; +using Services.Support.Exceptions; + +namespace Services.Tests.Domain; + +public class SpendingGroupServiceTests +{ + [Fact] + public async Task Create_ReturnsSpendingGroupViewModel() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new SpendingGroupDto()); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + var result = await spendingGroupService.Create(new()); + + spendingGroupRepoMock.Verify(repo => repo.Create(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public async Task GetList_ReturnsSpendingGroupViewModels() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.GetList(It.IsAny())).ReturnsAsync(_getAllSpendingGroups()); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + var result = await spendingGroupService.GetList(); + + spendingGroupRepoMock.Verify(repo => repo.GetList(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType>(result.ToList()); + } + + [Fact] + public async Task Delete_ReturnsSpendingGroupViewModel() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync(new SpendingGroupDto()); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + var result = await spendingGroupService.Delete(new()); + + spendingGroupRepoMock.Verify(repo => repo.Delete(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public void Delete_WhenSpendingGroupNotFound_ThrowsEntityNotFoundException() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync((SpendingGroupDto)null); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + Assert.ThrowsAsync(() => spendingGroupService.Delete(new())); + } + + [Fact] + public async Task Update_ReturnsSpendingGroupViewModel() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync(new SpendingGroupDto()); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + var result = await spendingGroupService.Update(new()); + + spendingGroupRepoMock.Verify(repo => repo.Update(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public void Update_WhenSpendingGroupNotFound_ThrowsEntityNotFoundException() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync((SpendingGroupDto)null); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + Assert.ThrowsAsync(() => spendingGroupService.Update(new())); + } + + [Fact] + public async Task GetDetails_ReturnsSpendingGroupViewModel() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync(new SpendingGroupDto()); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + var result = await spendingGroupService.GetDetails(new()); + + spendingGroupRepoMock.Verify(repo => repo.Get(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public void GetDetails_WhenSpendingGroupNotFound_ThrowsEntityNotFoundException() + { + var spendingGroupRepoMock = new Mock(); + spendingGroupRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync((SpendingGroupDto)null); + var spendingGroupService = new SpendingGroupService(spendingGroupRepoMock.Object); + + Assert.ThrowsAsync(() => spendingGroupService.GetDetails(new())); + } + + private IEnumerable _getAllSpendingGroups() => new List() + { + new() { Id = Guid.NewGuid(), Name = "Group 1" }, + new() { Id = Guid.NewGuid(), Name = "Group 2" } + }; +} diff --git a/back/Services.Tests/Domain/SpendingPlanServiceTests.cs b/back/Services.Tests/Domain/SpendingPlanServiceTests.cs new file mode 100644 index 0000000..f388004 --- /dev/null +++ b/back/Services.Tests/Domain/SpendingPlanServiceTests.cs @@ -0,0 +1,101 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.ViewModels; +using Moq; +using Services.Domain; +using Services.Support.Exceptions; + +namespace Services.Tests.Domain; + +public class SpendingPlanServiceTests +{ + [Fact] + public async Task Create_ReturnsSpendingPlanViewModel() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.Create(It.IsAny())).ReturnsAsync(new SpendingPlanDto()); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + var result = await spendingPlanService.Create(new()); + + spendingPlanRepoMock.Verify(repo => repo.Create(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + + [Fact] + public async Task Update_WhenPlanExists_ThenUpdatePlan_ReturnsSpendingPlanViewModel() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.Update(It.IsAny())) + .ReturnsAsync(new SpendingPlanDto()); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + var result = await spendingPlanService.Update(new()); + + spendingPlanRepoMock.Verify(repo => repo.Update(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public async Task Update_WhenPlanNotFound_ThenThrowsEntityNotFoundException() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.Update(It.IsAny())) + .ReturnsAsync((SpendingPlanDto)null); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + await Assert.ThrowsAsync(() => spendingPlanService.Update(new())); + } + + [Fact] + public async Task Delete_WhenPlanExists_ThenDeletePlan_ReturnsSpendingPlanViewModel() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.Delete(It.IsAny())) + .ReturnsAsync(new SpendingPlanDto()); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + var result = await spendingPlanService.Delete(new()); + + spendingPlanRepoMock.Verify(repo => repo.Delete(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public async Task Delete_WhenPlanNotFound_ThenThrowsEntityNotFoundException() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.Delete(It.IsAny())) + .ReturnsAsync((SpendingPlanDto)null); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + await Assert.ThrowsAsync(() => spendingPlanService.Delete(new())); + } + + [Fact] + public async Task GetList_ReturnsSpendingPlanViewModels() + { + var spendingPlanRepoMock = new Mock(); + spendingPlanRepoMock.Setup(repo => repo.GetList(It.IsAny())) + .ReturnsAsync(_getAllSpendingPlans()); + var spendingPlanService = new SpendingPlanService(spendingPlanRepoMock.Object); + + var result = await spendingPlanService.GetList(new()); + + spendingPlanRepoMock.Verify(repo => repo.GetList(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType>(result.ToList()); + Assert.Equal(2, result.Count()); + } + + private IEnumerable _getAllSpendingPlans() => new List() + { + new() { Id = Guid.NewGuid(), StartAt = DateTime.Now, EndAt = DateTime.Now, Sum = 100 }, + new() { Id = Guid.NewGuid(), StartAt = DateTime.Now, EndAt = DateTime.Now, Sum = 200 } + }; +} \ No newline at end of file diff --git a/back/Services.Tests/Domain/UserServiceTests.cs b/back/Services.Tests/Domain/UserServiceTests.cs new file mode 100644 index 0000000..1e4fd0c --- /dev/null +++ b/back/Services.Tests/Domain/UserServiceTests.cs @@ -0,0 +1,74 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.ViewModels; +using Moq; +using Services.Domain; +using Services.Support.Exceptions; + +namespace Services.Tests.Domain; + +public class UserServiceTests +{ + [Fact] + public async Task Delete_WhenUserExists_ThenDeleteUser_ReturnsUserViewModel() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync(new UserDto()); + var userService = new UserService(userRepoMock.Object); + + var result = await userService.Delete(new UserSearch()); + + userRepoMock.Verify(repo => repo.Delete(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public void Delete_WhenUserNotExists_ThenThrowsUserNotFoundException() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Delete(It.IsAny())).ReturnsAsync((UserDto?)null); + var userService = new UserService(userRepoMock.Object); + + Assert.ThrowsAsync(() => userService.Delete(new UserSearch())); + } + + [Fact] + public async Task Update_WhenUserExists_ThenUpdateUser_ReturnsUserViewModel() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync(new UserDto()); + var userService = new UserService(userRepoMock.Object); + + var result = await userService.UpdateUserData(new UserDto()); + + userRepoMock.Verify(repo => repo.Update(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public void Update_WhenUserNotFound_ThenThrowsUserNotFoundException() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Update(It.IsAny())).ReturnsAsync((UserDto?)null); + var userService = new UserService(userRepoMock.Object); + + Assert.ThrowsAsync(() => userService.UpdateUserData(new UserDto())); + } + + [Fact] + public async Task GetDetails_ReturnsUserViewModel() + { + var userRepoMock = new Mock(); + userRepoMock.Setup(repo => repo.Get(It.IsAny())).ReturnsAsync(new UserDto()); + var userService = new UserService(userRepoMock.Object); + + var result = await userService.GetDetails(new UserSearch()); + + userRepoMock.Verify(repo => repo.Get(It.IsAny()), Times.Once); + Assert.NotNull(result); + Assert.IsType(result); + } +} \ No newline at end of file diff --git a/back/Services.Tests/Services.Tests.csproj b/back/Services.Tests/Services.Tests.csproj new file mode 100644 index 0000000..a060883 --- /dev/null +++ b/back/Services.Tests/Services.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/back/Services.Tests/Support/Fakes/Database/DbFake.cs b/back/Services.Tests/Support/Fakes/Database/DbFake.cs new file mode 100644 index 0000000..0b55620 --- /dev/null +++ b/back/Services.Tests/Support/Fakes/Database/DbFake.cs @@ -0,0 +1,13 @@ +using Contracts.DTO; + +namespace Services.Tests.Support.Fakes.Database; + +internal static class DbFake +{ + public static List Users = new(); + + public static void ClearDb() + { + Users.Clear(); + } +} \ No newline at end of file diff --git a/back/Services.Tests/Support/Fakes/Repositories/UserRepoFake.cs b/back/Services.Tests/Support/Fakes/Repositories/UserRepoFake.cs new file mode 100644 index 0000000..3b70c88 --- /dev/null +++ b/back/Services.Tests/Support/Fakes/Repositories/UserRepoFake.cs @@ -0,0 +1,55 @@ +using System.Data.Common; +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Services.Tests.Support.Fakes.Database; + +namespace Services.Tests.Support.Fakes.Repositories; + +internal class UserRepoFake : IUserRepo +{ + public async Task ChangeBalance(UserSearch search, decimal amount) + { + var user = DbFake.Users.FirstOrDefault(u => u.Id == search.Id); + if (user != null) + { + user.Balance += amount; + return await Task.FromResult(true); + } + return await Task.FromResult(false); + } + + public async Task Create(UserDto user) + { + DbFake.Users.Add(user); + return await Task.FromResult(user); + } + + public async Task Delete(UserSearch search) + { + var user = DbFake.Users.FirstOrDefault(u => u.Id == search.Id); + if (user != null) + { + DbFake.Users.Remove(user); + } + return await Task.FromResult(user); + } + + public async Task Get(UserSearch search) + { + return await Task.FromResult(DbFake.Users.FirstOrDefault(u => u.Id == search.Id)); + } + + public async Task Update(UserDto user) + { + var existingUser = DbFake.Users.FirstOrDefault(u => u.Id == user.Id); + if (existingUser != null) + { + existingUser.Name = user.Name; + existingUser.Password = user.Password; + DbFake.Users.Remove(existingUser); + DbFake.Users.Add(existingUser); + } + return await Task.FromResult(existingUser); + } +} diff --git a/back/Services/Domain/ChangeRecordService.cs b/back/Services/Domain/ChangeRecordService.cs index 45ed858..51e1e03 100644 --- a/back/Services/Domain/ChangeRecordService.cs +++ b/back/Services/Domain/ChangeRecordService.cs @@ -4,6 +4,7 @@ using Contracts.Repositories; using Contracts.SearchModels; using Contracts.Services; using Contracts.ViewModels; +using Services.Support.Exceptions; namespace Services.Domain; @@ -32,7 +33,7 @@ public class ChangeRecordService : IChangeRecordService var record = await _changeRecordRepo.Delete(search); if (record == null) { - throw new EntryPointNotFoundException("При удалении не получилось найти запись измнения баланса"); + throw new EntityNotFoundException("При удалении не получилось найти запись измнения баланса"); } // Возвращает баланс обратно await _userRepo.ChangeBalance(new() { Id = record.UserId }, -record.Sum); @@ -51,7 +52,7 @@ public class ChangeRecordService : IChangeRecordService var record = await _changeRecordRepo.Update(model); if (record == null) { - throw new EntryPointNotFoundException("При изменении не получилось найти запись измнения баланса"); + throw new EntityNotFoundException("При изменении не получилось найти запись измнения баланса"); } await _userRepo.ChangeBalance(new() { Id = model.UserId }, model.Sum - record.Sum); return record.ToView();