From 7190f4768a180fbc6df3442bdc97a31f30a96c23 Mon Sep 17 00:00:00 2001 From: admEug Date: Tue, 19 Aug 2025 15:28:47 +0300 Subject: [PATCH 1/4] Added some changes in the launch settings --- Blazorcrud.Client/Properties/launchSettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Blazorcrud.Client/Properties/launchSettings.json b/Blazorcrud.Client/Properties/launchSettings.json index 8f173be..63c8722 100644 --- a/Blazorcrud.Client/Properties/launchSettings.json +++ b/Blazorcrud.Client/Properties/launchSettings.json @@ -13,7 +13,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "https://localhost:5002;http://localhost:5003", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From 097f80f18a9352ee366bb429f984fc66831f407f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:53:48 +0000 Subject: [PATCH 2/4] This commit adds unit and integration tests for the Blazorcrud.Server project. Unit tests are added for the `PersonController`. Moq is used to mock the `IPersonRepository`. Integration tests are added for the `PersonController` using `WebApplicationFactory`. The tests make requests to the API endpoints and verify the responses. The following changes were made: - Added `Blazorcrud.Server.Tests` project for unit tests. - Added `Blazorcrud.Server.IntegrationTests` project for integration tests. - Added unit tests for `PersonController`. - Added integration tests for `PersonController`. - Made the `Program` class public so that it can be accessed by the integration test project. --- .../Blazorcrud.Server.IntegrationTests.csproj | 30 +++++ .../GlobalUsings.cs | 1 + .../PersonControllerTests.cs | 37 ++++++ .../UnitTest1.cs | 10 ++ .../Blazorcrud.Server.Tests.csproj | 30 +++++ Blazorcrud.Server.Tests/GlobalUsings.cs | 1 + .../PersonControllerTests.cs | 113 ++++++++++++++++++ Blazorcrud.Server.Tests/UnitTest1.cs | 10 ++ Blazorcrud.Server/Blazorcrud.Server.csproj | 3 + Blazorcrud.Server/PublicProgram.cs | 1 + 10 files changed, 236 insertions(+) create mode 100644 Blazorcrud.Server.IntegrationTests/Blazorcrud.Server.IntegrationTests.csproj create mode 100644 Blazorcrud.Server.IntegrationTests/GlobalUsings.cs create mode 100644 Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs create mode 100644 Blazorcrud.Server.IntegrationTests/UnitTest1.cs create mode 100644 Blazorcrud.Server.Tests/Blazorcrud.Server.Tests.csproj create mode 100644 Blazorcrud.Server.Tests/GlobalUsings.cs create mode 100644 Blazorcrud.Server.Tests/PersonControllerTests.cs create mode 100644 Blazorcrud.Server.Tests/UnitTest1.cs create mode 100644 Blazorcrud.Server/PublicProgram.cs diff --git a/Blazorcrud.Server.IntegrationTests/Blazorcrud.Server.IntegrationTests.csproj b/Blazorcrud.Server.IntegrationTests/Blazorcrud.Server.IntegrationTests.csproj new file mode 100644 index 0000000..6d8d145 --- /dev/null +++ b/Blazorcrud.Server.IntegrationTests/Blazorcrud.Server.IntegrationTests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/Blazorcrud.Server.IntegrationTests/GlobalUsings.cs b/Blazorcrud.Server.IntegrationTests/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/Blazorcrud.Server.IntegrationTests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs b/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs new file mode 100644 index 0000000..1061df1 --- /dev/null +++ b/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs @@ -0,0 +1,37 @@ +using System.Net; +using System.Net.Http.Json; +using System.Threading.Tasks; +using Blazorcrud.Server; +using Blazorcrud.Shared.Data; +using Blazorcrud.Shared.Models; +using Microsoft.AspNetCore.Mvc.Testing; +using Xunit; + +namespace Blazorcrud.Server.IntegrationTests +{ + public class PersonControllerTests : IClassFixture> + { + private readonly WebApplicationFactory _factory; + + public PersonControllerTests(WebApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task Get_People_Returns_Success_And_Content() + { + // Arrange + var client = _factory.CreateClient(); + + // Act + var response = await client.GetAsync("/api/person?page=1"); + + // Assert + response.EnsureSuccessStatusCode(); + var pagedResult = await response.Content.ReadFromJsonAsync>(); + Assert.NotNull(pagedResult); + Assert.IsType>(pagedResult); + } + } +} diff --git a/Blazorcrud.Server.IntegrationTests/UnitTest1.cs b/Blazorcrud.Server.IntegrationTests/UnitTest1.cs new file mode 100644 index 0000000..3cfd8ef --- /dev/null +++ b/Blazorcrud.Server.IntegrationTests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace Blazorcrud.Server.IntegrationTests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file diff --git a/Blazorcrud.Server.Tests/Blazorcrud.Server.Tests.csproj b/Blazorcrud.Server.Tests/Blazorcrud.Server.Tests.csproj new file mode 100644 index 0000000..9df6e81 --- /dev/null +++ b/Blazorcrud.Server.Tests/Blazorcrud.Server.Tests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/Blazorcrud.Server.Tests/GlobalUsings.cs b/Blazorcrud.Server.Tests/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/Blazorcrud.Server.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/Blazorcrud.Server.Tests/PersonControllerTests.cs b/Blazorcrud.Server.Tests/PersonControllerTests.cs new file mode 100644 index 0000000..679f698 --- /dev/null +++ b/Blazorcrud.Server.Tests/PersonControllerTests.cs @@ -0,0 +1,113 @@ +using Xunit; +using Moq; +using Blazorcrud.Server.Controllers; +using Blazorcrud.Server.Models; +using Blazorcrud.Shared.Models; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Blazorcrud.Shared.Data; +using System.Collections.Generic; + +namespace Blazorcrud.Server.Tests +{ + public class PersonControllerTests + { + private readonly Mock _mockRepo; + private readonly PersonController _controller; + + public PersonControllerTests() + { + _mockRepo = new Mock(); + _controller = new PersonController(_mockRepo.Object); + } + + [Fact] + public void GetPeople_Returns_OkResult_With_PagedResult_Of_Person() + { + // Arrange + var name = "Test"; + var page = 1; + var pagedResult = new PagedResult { Results = new List { new Person { PersonId = 1, FirstName = "Test" } } }; + _mockRepo.Setup(repo => repo.GetPeople(name, page)) + .Returns(pagedResult); + + // Act + var result = _controller.GetPeople(name, page); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType>(okResult.Value); + Assert.Single(returnValue.Results); + } + + [Fact] + public async Task GetPerson_Returns_OkResult_With_Person() + { + // Arrange + var id = 1; + var person = new Person { PersonId = id, FirstName = "Test" }; + _mockRepo.Setup(repo => repo.GetPerson(id)) + .ReturnsAsync(person); + + // Act + var result = await _controller.GetPerson(id); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(id, returnValue.PersonId); + } + + [Fact] + public async Task AddPerson_Returns_OkResult_With_Person() + { + // Arrange + var person = new Person { PersonId = 1, FirstName = "Test" }; + _mockRepo.Setup(repo => repo.AddPerson(person)) + .ReturnsAsync(person); + + // Act + var result = await _controller.AddPerson(person); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(person.PersonId, returnValue.PersonId); + } + + [Fact] + public async Task UpdatePerson_Returns_OkResult_With_Person() + { + // Arrange + var person = new Person { PersonId = 1, FirstName = "Test" }; + _mockRepo.Setup(repo => repo.UpdatePerson(person)) + .ReturnsAsync(person); + + // Act + var result = await _controller.UpdatePerson(person); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(person.PersonId, returnValue.PersonId); + } + + [Fact] + public async Task DeletePerson_Returns_OkResult_With_Person() + { + // Arrange + var id = 1; + var person = new Person { PersonId = id, FirstName = "Test" }; + _mockRepo.Setup(repo => repo.DeletePerson(id)) + .ReturnsAsync(person); + + // Act + var result = await _controller.DeletePerson(id); + + // Assert + var okResult = Assert.IsType(result); + var returnValue = Assert.IsType(okResult.Value); + Assert.Equal(id, returnValue.PersonId); + } + } +} diff --git a/Blazorcrud.Server.Tests/UnitTest1.cs b/Blazorcrud.Server.Tests/UnitTest1.cs new file mode 100644 index 0000000..b69cfce --- /dev/null +++ b/Blazorcrud.Server.Tests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace Blazorcrud.Server.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file diff --git a/Blazorcrud.Server/Blazorcrud.Server.csproj b/Blazorcrud.Server/Blazorcrud.Server.csproj index 323606c..0f1eaac 100644 --- a/Blazorcrud.Server/Blazorcrud.Server.csproj +++ b/Blazorcrud.Server/Blazorcrud.Server.csproj @@ -23,4 +23,7 @@ + + + \ No newline at end of file diff --git a/Blazorcrud.Server/PublicProgram.cs b/Blazorcrud.Server/PublicProgram.cs new file mode 100644 index 0000000..9a19438 --- /dev/null +++ b/Blazorcrud.Server/PublicProgram.cs @@ -0,0 +1 @@ +public partial class Program { } From 1c81b8077b949a0cab16d16fbdbb2e23beec0d9c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:54:52 +0000 Subject: [PATCH 3/4] This commit adds the `Blazorcrud.Server.Tests` and `Blazorcrud.Server.IntegrationTests` projects to the `Blazorcrud.sln` solution file. This was missed in the previous commit. --- Blazorcrud.sln | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Blazorcrud.sln b/Blazorcrud.sln index 1d2c739..a41ca43 100644 --- a/Blazorcrud.sln +++ b/Blazorcrud.sln @@ -9,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorcrud.Client", "Blazor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorcrud.Server", "Blazorcrud.Server\Blazorcrud.Server.csproj", "{75348867-CC83-4724-8011-5D5CB07010BE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorcrud.Server.Tests", "Blazorcrud.Server.Tests\Blazorcrud.Server.Tests.csproj", "{15AADED1-998B-44CB-83BE-4E206F496847}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorcrud.Server.IntegrationTests", "Blazorcrud.Server.IntegrationTests\Blazorcrud.Server.IntegrationTests.csproj", "{6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,5 +62,29 @@ Global {75348867-CC83-4724-8011-5D5CB07010BE}.Release|x64.Build.0 = Release|Any CPU {75348867-CC83-4724-8011-5D5CB07010BE}.Release|x86.ActiveCfg = Release|Any CPU {75348867-CC83-4724-8011-5D5CB07010BE}.Release|x86.Build.0 = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|x64.ActiveCfg = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|x64.Build.0 = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|x86.ActiveCfg = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Debug|x86.Build.0 = Debug|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|Any CPU.Build.0 = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|x64.ActiveCfg = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|x64.Build.0 = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|x86.ActiveCfg = Release|Any CPU + {15AADED1-998B-44CB-83BE-4E206F496847}.Release|x86.Build.0 = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|x64.ActiveCfg = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|x64.Build.0 = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|x86.ActiveCfg = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Debug|x86.Build.0 = Debug|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|Any CPU.Build.0 = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|x64.ActiveCfg = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|x64.Build.0 = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|x86.ActiveCfg = Release|Any CPU + {6525ED9C-1BD3-49B1-B04D-03CA6A068A3C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 9100dca45947d9993de6940437f045a372fab30c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:04:06 +0000 Subject: [PATCH 4/4] This commit adds more integration tests for the PersonController to cover all the endpoints. The following tests were added: - GetPerson(id) - AddPerson - UpdatePerson - DeletePerson A helper class was added to get a JWT token for authenticated requests. --- .../PersonControllerTests.cs | 107 ++++++++++++++++++ .../Utilities.cs | 25 ++++ 2 files changed, 132 insertions(+) create mode 100644 Blazorcrud.Server.IntegrationTests/Utilities.cs diff --git a/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs b/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs index 1061df1..1687824 100644 --- a/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs +++ b/Blazorcrud.Server.IntegrationTests/PersonControllerTests.cs @@ -33,5 +33,112 @@ public async Task Get_People_Returns_Success_And_Content() Assert.NotNull(pagedResult); Assert.IsType>(pagedResult); } + + [Fact] + public async Task Get_Person_By_Id_Returns_Success_And_Content() + { + // Arrange + var client = _factory.CreateClient(); + + // Act + var response = await client.GetAsync("/api/person/1"); + + // Assert + response.EnsureSuccessStatusCode(); + var person = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(person); + Assert.Equal(1, person.PersonId); + } + + [Fact] + public async Task Add_Person_Returns_Success() + { + // Arrange + var client = _factory.CreateClient(); + var token = await Utilities.GetJwtAsync(client); + client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var newPerson = new Person + { + FirstName = "John", + LastName = "Doe", + Gender = Gender.Male, + PhoneNumber = "1234567890", + Addresses = new() + { + new Address { Street = "123 Main St", City = "Anytown", State = "CA", ZipCode = "12345" } + } + }; + + // Act + var response = await client.PostAsJsonAsync("/api/person", newPerson); + + // Assert + response.EnsureSuccessStatusCode(); + var person = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(person); + Assert.Equal("John", person.FirstName); + } + + [Fact] + public async Task Update_Person_Returns_Success() + { + // Arrange + var client = _factory.CreateClient(); + var token = await Utilities.GetJwtAsync(client); + client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var newPerson = new Person + { + FirstName = "Jane", + LastName = "Doe", + Gender = Gender.Female, + PhoneNumber = "1234567890", + Addresses = new() + { + new Address { Street = "123 Main St", City = "Anytown", State = "CA", ZipCode = "12345" } + } + }; + var response = await client.PostAsJsonAsync("/api/person", newPerson); + response.EnsureSuccessStatusCode(); + var person = await response.Content.ReadFromJsonAsync(); + + // Act + person.FirstName = "Janet"; + response = await client.PutAsJsonAsync("/api/person", person); + + // Assert + response.EnsureSuccessStatusCode(); + var updatedPerson = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(updatedPerson); + Assert.Equal("Janet", updatedPerson.FirstName); + } + + [Fact] + public async Task Delete_Person_Returns_Success() + { + // Arrange + var client = _factory.CreateClient(); + var token = await Utilities.GetJwtAsync(client); + client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + var newPerson = new Person + { + FirstName = "Jim", + LastName = "Doe", + Gender = Gender.Male, + PhoneNumber = "1234567890", + Addresses = new() + { + new Address { Street = "123 Main St", City = "Anytown", State = "CA", ZipCode = "12345" } + } + }; + var response = await client.PostAsJsonAsync("/api/person", newPerson); + response.EnsureSuccessStatusCode(); + var person = await response.Content.ReadFromJsonAsync(); + + // Act + response = await client.DeleteAsync($"/api/person/{person.PersonId}"); + + // Assert + response.EnsureSuccessStatusCode(); + } } } diff --git a/Blazorcrud.Server.IntegrationTests/Utilities.cs b/Blazorcrud.Server.IntegrationTests/Utilities.cs new file mode 100644 index 0000000..ea2c60d --- /dev/null +++ b/Blazorcrud.Server.IntegrationTests/Utilities.cs @@ -0,0 +1,25 @@ +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading.Tasks; +using Blazorcrud.Server.Authorization; +using Blazorcrud.Shared.Models; +using Microsoft.AspNetCore.Mvc.Testing; + +namespace Blazorcrud.Server.IntegrationTests +{ + public static class Utilities + { + public static async Task GetJwtAsync(HttpClient client) + { + var login = new AuthenticateRequest + { + Username = "admin", + Password = "admin" + }; + var response = await client.PostAsJsonAsync("/api/user/authenticate", login); + response.EnsureSuccessStatusCode(); + var authResponse = await response.Content.ReadFromJsonAsync(); + return authResponse.Token; + } + } +}