diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 477ff9c..270cf32 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -36,14 +36,12 @@ jobs:
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Test
+ working-directory: Tests/CleanAspCore.Api.Tests
run: >
- dotnet test
+ dotnet run
--no-build
--configuration Release
- --verbosity normal
- --logger GitHubActions
- --
- RunConfiguration.CollectSourceInformation=true
+ --report-trx
- name: dotnet publish
working-directory: CleanAspCore.Api
run: dotnet publish --no-build -c Release -o ${{env.DOTNET_ROOT}}/myapp
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 3045283..de0f100 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -3,6 +3,10 @@
name: .NET
+permissions:
+ checks: write
+ pull-requests: write
+
on:
push:
branches: [ "main" ]
@@ -35,12 +39,38 @@ jobs:
- name: Check code formatting
run: dotnet format --no-restore --verify-no-changes -v diag
- name: Build
- run: dotnet build --no-restore
+ run: dotnet build
+ --no-restore
+ --configuration Release
- name: Test
+ working-directory: Tests/CleanAspCore.Api.Tests
run: >
- dotnet test
+ dotnet run
--no-build
- --verbosity normal
- --logger GitHubActions
- --
- RunConfiguration.CollectSourceInformation=true
+ --configuration Release
+ --coverage
+ --coverage-output-format cobertura
+ --report-trx
+ - name: Publish Test Results
+ uses: EnricoMi/publish-unit-test-result-action@v2
+ if: always()
+ with:
+ files: |
+ **/*.trx
+ - name: Code Coverage Report
+ uses: irongut/CodeCoverageSummary@v1.3.0
+ with:
+ filename: "**/*.cobertura.xml"
+ badge: true
+ format: markdown
+ hide_branch_rate: false
+ hide_complexity: true
+ indicators: true
+ output: both
+
+ - name: Add Coverage PR Comment
+ uses: marocchino/sticky-pull-request-comment@v2
+ if: github.event_name == 'pull_request'
+ with:
+ recreate: true
+ path: code-coverage-results.md
diff --git a/CleanAspCore.sln b/CleanAspCore.sln
index 3991631..170bceb 100644
--- a/CleanAspCore.sln
+++ b/CleanAspCore.sln
@@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
Readme.md = Readme.md
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
.github\workflows\deploy.yml = .github\workflows\deploy.yml
+ Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanAspCore.Api.Tests", "Tests\CleanAspCore.Api.Tests\CleanAspCore.Api.Tests.csproj", "{4B45D679-E787-4236-BD9A-383364CD0E6F}"
diff --git a/Directory.Packages.props b/Directory.Packages.props
index e550762..459bafe 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -23,10 +23,9 @@
-
-
-
-
+
+
+
diff --git a/Tests/CleanAspCore.Api.Tests/CleanAspCore.Api.Tests.csproj b/Tests/CleanAspCore.Api.Tests/CleanAspCore.Api.Tests.csproj
index a2c905f..0ebbe9a 100644
--- a/Tests/CleanAspCore.Api.Tests/CleanAspCore.Api.Tests.csproj
+++ b/Tests/CleanAspCore.Api.Tests/CleanAspCore.Api.Tests.csproj
@@ -6,23 +6,11 @@
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
+
diff --git a/Tests/CleanAspCore.Api.Tests/Data/MigrationTests.cs b/Tests/CleanAspCore.Api.Tests/Data/MigrationTests.cs
index 6b8f981..38cab40 100644
--- a/Tests/CleanAspCore.Api.Tests/Data/MigrationTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Data/MigrationTests.cs
@@ -1,43 +1,32 @@
-using System.Collections;
-using CleanAspCore.Data;
+using CleanAspCore.Data;
using CleanAspCore.TestUtils.DataBaseSetup;
using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Testcontainers.MsSql;
namespace CleanAspCore.Api.Tests.Data;
-[FixtureLifeCycle(LifeCycle.SingleInstance)]
-[Parallelizable(ParallelScope.Self)]
-internal sealed class MigrationTests
+internal sealed class MigrationTests(MsSqlContainer databaseContainer, ILogger logger)
{
-#pragma warning disable NUnit1032
- private MsSqlContainer _databaseContainer = null!;
-#pragma warning restore NUnit1032
- private ILogger _logger = null!;
- private AsyncServiceScope _scope;
-
- [SetUp]
- public void BeforeTestCase()
+ public static IEnumerable> MigrationTestCases()
{
- _scope = GlobalSetup.Provider.CreateAsyncScope();
- _databaseContainer = _scope.ServiceProvider.GetRequiredService();
- _logger = _scope.ServiceProvider.GetRequiredService>();
- }
+ using DbContext context = new HrContext();
+ var migrations = context.GenerateMigrationScripts();
- [TearDown]
- public async Task AfterTestCase()
- {
- await _scope.DisposeAsync();
+ foreach (var migration in migrations)
+ {
+ yield return () => migration;
+ }
}
- [TestCaseSource(typeof(MigrationTestCases))]
+ [Test]
+ [MethodDataSource(nameof(MigrationTestCases))]
+ [NotInParallel("MigrationsTest")]
public async Task MigrationsUpAndDown_NoErrors(MigrationScript migration)
{
var databaseName = "MigrationsTest";
- await _databaseContainer.CreateDatabase(databaseName);
- var migrator = new SqlMigrator(_databaseContainer, _logger, databaseName);
+ await databaseContainer.CreateDatabase(databaseName);
+ var migrator = new SqlMigrator(databaseContainer, logger, databaseName);
var upResult = await migrator.Up(migration);
upResult.ExitCode.Should().Be(0, $"Error during migration up: {upResult.Stderr}");
var downResult = await migrator.Down(migration);
@@ -53,19 +42,4 @@ public void ModelShouldNotHavePendingModelChanges()
var hasPendingModelChanges = context.Database.HasPendingModelChanges();
hasPendingModelChanges.Should().BeFalse();
}
-
- [SuppressMessage("CodeQuality", "CA1812:Avoid uninstantiated internal classes")]
- private sealed class MigrationTestCases : IEnumerable
- {
- public IEnumerator GetEnumerator()
- {
- using DbContext context = new HrContext();
- var migrations = context.GenerateMigrationScripts();
-
- foreach (var migration in migrations)
- {
- yield return new TestCaseData(migration);
- }
- }
- }
}
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/AddDepartmentsTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/AddDepartmentsTests.cs
index 8cb7b4c..8b0f7b7 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/AddDepartmentsTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/AddDepartmentsTests.cs
@@ -2,7 +2,7 @@
namespace CleanAspCore.Api.Tests.Endpoints.Departments;
-internal sealed class AddDepartmentsTests : TestBase
+internal sealed class AddDepartmentsTests(TestWebApi sut)
{
[Test]
public async Task CreateDepartment_IsAdded()
@@ -11,12 +11,12 @@ public async Task CreateDepartment_IsAdded()
var department = new CreateDepartmentRequestFaker().Generate();
//Act
- var response = await Sut.CreateClientFor().CreateDepartment(department);
+ var response = await sut.CreateClientFor().CreateDepartment(department);
//Assert
await response.AssertStatusCode(HttpStatusCode.Created);
var createdId = response.GetGuidFromLocationHeader();
- Sut.AssertDatabase(context =>
+ sut.AssertDatabase(context =>
{
context.Departments.Should().BeEquivalentTo(new[] { new { Id = createdId } });
});
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/GetDepartmentByIdTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/GetDepartmentByIdTests.cs
index 68105b3..760e220 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/GetDepartmentByIdTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Departments/GetDepartmentByIdTests.cs
@@ -1,19 +1,19 @@
namespace CleanAspCore.Api.Tests.Endpoints.Departments;
-internal sealed class GetDepartmentByIdTests : TestBase
+internal sealed class GetDepartmentByIdTests(TestWebApi sut)
{
[Test]
public async Task GetDepartmentById_ReturnsExpectedDepartment()
{
//Arrange
var department = new DepartmentFaker().Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Departments.Add(department);
});
//Act
- var response = await Sut.CreateClientFor().GetDepartmentById(department.Id);
+ var response = await sut.CreateClientFor().GetDepartmentById(department.Id);
//Assert
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/CreateEmployeeTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/CreateEmployeeTests.cs
index d6a396b..ab92d84 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/CreateEmployeeTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/CreateEmployeeTests.cs
@@ -3,50 +3,51 @@
namespace CleanAspCore.Api.Tests.Endpoints.Employees;
-internal sealed class CreateEmployeeTests : TestBase
+internal sealed class CreateEmployeeTests(TestWebApi sut)
{
[Test]
public async Task CreateEmployee_IsAdded()
{
//Arrange
var createEmployeeRequest = new CreateEmployeeRequestFaker().Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Departments.Add(new DepartmentFaker().RuleFor(x => x.Id, createEmployeeRequest.DepartmentId).Generate());
context.Jobs.Add(new JobFaker().RuleFor(x => x.Id, createEmployeeRequest.JobId).Generate());
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).CreateEmployee(createEmployeeRequest);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).CreateEmployee(createEmployeeRequest);
//Assert
await response.AssertStatusCode(HttpStatusCode.Created);
var createdId = response.GetGuidFromLocationHeader();
- Sut.AssertDatabase(context =>
+ sut.AssertDatabase(context =>
{
context.Employees.Should().BeEquivalentTo(new[] { new { Id = createdId } });
});
}
- private static readonly TestScenario<(FakerConfigurator, string[])>[] _validationCases =
- [
- new((string)"FirstName is null",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.FirstName, (string?)null), ["FirstName"])),
- new((string)"LastName is null",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.LastName, (string?)null), ["LastName"])),
- new((string)"Gender is null",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.Gender, (string?)null), ["Gender"])),
- new((string)"Email is null",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.Email, (string?)null), ["Email"])),
- new((string)"Invalid email",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.Email, "this is not a valid email address"), ["Email"])),
- new((string)"Job does not exist",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.JobId, Guid.NewGuid()), ["JobId"])),
- new((string)"Department does not exist",
- ((FakerConfigurator, string[]))(x => x.RuleFor(y => y.DepartmentId, Guid.NewGuid()), ["DepartmentId"])),
- ];
+ public static IEnumerable, string[])>>> ValidationTestCases()
+ {
+ yield return () => new((string)"FirstName is null",
+ (x => x.RuleFor(y => y.FirstName, (string?)null), ["FirstName"]));
+ yield return () => new((string)"LastName is null",
+ (x => x.RuleFor(y => y.LastName, (string?)null), ["LastName"]));
+ yield return () => new((string)"Gender is null",
+ (x => x.RuleFor(y => y.Gender, (string?)null), ["Gender"]));
+ yield return () => new((string)"Email is null",
+ (x => x.RuleFor(y => y.Email, (string?)null), ["Email"]));
+ yield return () => new((string)"Invalid email",
+ (x => x.RuleFor(y => y.Email, "this is not a valid email address"), ["Email"]));
+ yield return () => new((string)"Job does not exist",
+ (x => x.RuleFor(y => y.JobId, Guid.NewGuid()), ["JobId"]));
+ yield return () => new((string)"Department does not exist",
+ (x => x.RuleFor(y => y.DepartmentId, Guid.NewGuid()), ["DepartmentId"]));
+ }
- [TestCaseSource(nameof(_validationCases))]
+ [Test]
+ [MethodDataSource(nameof(ValidationTestCases))]
public async Task CreateEmployee_InvalidRequest_ReturnsBadRequest(TestScenario<(FakerConfigurator configurator, string[] expectedErrors)> scenario)
{
//Arrange
@@ -57,18 +58,18 @@ public async Task CreateEmployee_InvalidRequest_ReturnsBadRequest(TestScenario<(
.RuleFor(x => x.DepartmentId, departmentId)
.RuleFor(x => x.JobId, jobId)).Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Departments.Add(new DepartmentFaker().RuleFor(x => x.Id, departmentId).Generate());
context.Jobs.Add(new JobFaker().RuleFor(x => x.Id, jobId).Generate());
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).CreateEmployee(createEmployeeRequest);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).CreateEmployee(createEmployeeRequest);
//Assert
await response.AssertBadRequest(scenario.Input.expectedErrors);
- Sut.AssertDatabase(context =>
+ sut.AssertDatabase(context =>
{
context.Employees.Should().BeEmpty();
});
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/DeleteEmployeeByIdTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/DeleteEmployeeByIdTests.cs
index 9f98a7a..4559060 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/DeleteEmployeeByIdTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/DeleteEmployeeByIdTests.cs
@@ -1,23 +1,23 @@
namespace CleanAspCore.Api.Tests.Endpoints.Employees;
-internal sealed class DeleteEmployeeByIdTests : TestBase
+internal sealed class DeleteEmployeeByIdTests(TestWebApi sut)
{
[Test]
public async Task DeleteEmployeeById_IsDeleted()
{
//Arrange
var employee = new EmployeeFaker().Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Employees.Add(employee);
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).DeleteEmployeeById(employee.Id);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).DeleteEmployeeById(employee.Id);
//Assert
await response.AssertStatusCode(HttpStatusCode.NoContent);
- Sut.AssertDatabase(context => { context.Employees.Should().BeEmpty(); });
+ sut.AssertDatabase(context => { context.Employees.Should().BeEmpty(); });
}
[Test]
@@ -27,7 +27,7 @@ public async Task DeleteEmployeeById_DoesNotExist_ReturnsNotFound()
var id = Guid.NewGuid();
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).DeleteEmployeeById(id);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).DeleteEmployeeById(id);
//Assert
await response.AssertStatusCode(HttpStatusCode.NotFound);
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeeByIdTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeeByIdTests.cs
index f92578d..6997d99 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeeByIdTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeeByIdTests.cs
@@ -1,19 +1,19 @@
namespace CleanAspCore.Api.Tests.Endpoints.Employees;
-internal sealed class GetEmployeeByIdTests : TestBase
+internal sealed class GetEmployeeByIdTests(TestWebApi sut)
{
[Test]
public async Task GetEmployeeById_ReturnsExpectedEmployee()
{
//Arrange
var employee = new EmployeeFaker().Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Employees.Add(employee);
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployeeById(employee.Id);
+ var response = await sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployeeById(employee.Id);
//Assert
await response.AssertStatusCode(HttpStatusCode.OK);
@@ -27,7 +27,7 @@ public async Task GetEmployeeById_DoesNotExist_ReturnsNotFound()
var employee = new EmployeeFaker().Generate();
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployeeById(employee.Id);
+ var response = await sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployeeById(employee.Id);
//Assert
await response.AssertStatusCode(HttpStatusCode.NotFound);
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeesTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeesTests.cs
index 00f3ce2..46affbc 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeesTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/GetEmployeesTests.cs
@@ -1,12 +1,12 @@
namespace CleanAspCore.Api.Tests.Endpoints.Employees;
-internal sealed class GetEmployees : TestBase
+internal sealed class GetEmployees(TestWebApi sut)
{
[Test]
public async Task? GetEmployees_NoEmployees_ReturnsEmptyPage()
{
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(1, 10);
+ var response = await sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(1, 10);
//Assert
await response.AssertStatusCode(HttpStatusCode.OK);
@@ -29,13 +29,13 @@ public async Task GetEmployees_FirstPage_ReturnsExpectedEmployees()
.RuleFor(x => x.Department, department)
.RuleFor(x => x.Job, job)
.Generate(15);
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Employees.AddRange(employees);
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(1, 10);
+ var response = await sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(1, 10);
//Assert
await response.AssertStatusCode(HttpStatusCode.OK);
@@ -62,13 +62,13 @@ public async Task GetEmployees_SecondPage_ReturnsExpectedEmployees()
.RuleFor(x => x.Department, department)
.RuleFor(x => x.Job, job)
.Generate(15);
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Employees.AddRange(employees);
});
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(2, 10);
+ var response = await sut.CreateClientFor(ClaimConstants.ReadRole).GetEmployees(2, 10);
//Assert
await response.AssertStatusCode(HttpStatusCode.OK);
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/UpdateEmployeeByIdTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/UpdateEmployeeByIdTests.cs
index 813711c..a7ce98b 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/UpdateEmployeeByIdTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Employees/UpdateEmployeeByIdTests.cs
@@ -2,23 +2,23 @@
namespace CleanAspCore.Api.Tests.Endpoints.Employees;
-internal sealed class UpdateEmployeeByIdTests : TestBase
+internal sealed class UpdateEmployeeByIdTests(TestWebApi sut)
{
[Test]
public async Task UpdateEmployeeById_IsUpdated()
{
//Arrange
var employee = new EmployeeFaker().Generate();
- Sut.SeedData(context => { context.Employees.Add(employee); });
+ sut.SeedData(context => { context.Employees.Add(employee); });
UpdateEmployeeRequest updateEmployeeRequest = new() { FirstName = "Updated" };
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).UpdateEmployeeById(employee.Id, updateEmployeeRequest);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).UpdateEmployeeById(employee.Id, updateEmployeeRequest);
//Assert
await response.AssertStatusCode(HttpStatusCode.NoContent);
- Sut.AssertDatabase(context =>
+ sut.AssertDatabase(context =>
{
context.Employees.Should().BeEquivalentTo(new[]
{
@@ -40,7 +40,7 @@ public async Task UpdateEmployeeById_DoesNotExist_ReturnsNotFound()
UpdateEmployeeRequest updateEmployeeRequest = new() { FirstName = "Updated" };
//Act
- var response = await Sut.CreateClientFor(ClaimConstants.WriteRole).UpdateEmployeeById(employee.Id, updateEmployeeRequest);
+ var response = await sut.CreateClientFor(ClaimConstants.WriteRole).UpdateEmployeeById(employee.Id, updateEmployeeRequest);
//Assert
await response.AssertStatusCode(HttpStatusCode.NotFound);
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/CreateJobTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/CreateJobTests.cs
index 39a7c0c..a99630b 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/CreateJobTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/CreateJobTests.cs
@@ -2,7 +2,7 @@
namespace CleanAspCore.Api.Tests.Endpoints.Jobs;
-internal sealed class CreateJobTests : TestBase
+internal sealed class CreateJobTests(TestWebApi sut)
{
[Test]
public async Task CreateJob_IsAdded()
@@ -11,12 +11,12 @@ public async Task CreateJob_IsAdded()
var createJobRequest = new CreateJobRequestFaker().Generate();
//Act
- var response = await Sut.CreateClientFor().CreateJob(createJobRequest);
+ var response = await sut.CreateClientFor().CreateJob(createJobRequest);
//Assert
await response.AssertStatusCode(HttpStatusCode.Created);
var createdId = response.GetGuidFromLocationHeader();
- Sut.AssertDatabase(context =>
+ sut.AssertDatabase(context =>
{
context.Jobs.Should().BeEquivalentTo(new[] { new { Id = createdId } });
});
diff --git a/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/GetJobByIdTests.cs b/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/GetJobByIdTests.cs
index 86f8f2a..2246ad9 100644
--- a/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/GetJobByIdTests.cs
+++ b/Tests/CleanAspCore.Api.Tests/Endpoints/Jobs/GetJobByIdTests.cs
@@ -1,19 +1,19 @@
namespace CleanAspCore.Api.Tests.Endpoints.Jobs;
-internal sealed class GetJobByIdTests : TestBase
+internal sealed class GetJobByIdTests(TestWebApi sut)
{
[Test]
public async Task GetJobById_ReturnsExpectedJob()
{
//Arrange
var job = new JobFaker().Generate();
- Sut.SeedData(context =>
+ sut.SeedData(context =>
{
context.Jobs.Add(job);
});
//Act
- var response = await Sut.CreateClientFor().GetJobById(job.Id);
+ var response = await sut.CreateClientFor().GetJobById(job.Id);
//Assert
await response.AssertStatusCode(HttpStatusCode.OK);
diff --git a/Tests/CleanAspCore.Api.Tests/GlobalSetup.cs b/Tests/CleanAspCore.Api.Tests/GlobalSetup.cs
deleted file mode 100644
index 2870b25..0000000
--- a/Tests/CleanAspCore.Api.Tests/GlobalSetup.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using CleanAspCore.Api.TestUtils.Logging;
-using CleanAspCore.Data;
-using CleanAspCore.TestUtils.DataBaseSetup;
-using Microsoft.Extensions.DependencyInjection;
-
-[assembly: FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
-[assembly: Parallelizable(ParallelScope.Children)]
-[assembly: ExcludeFromCodeCoverage]
-
-namespace CleanAspCore.Api.Tests;
-
-[SetUpFixture]
-internal sealed class GlobalSetup
-{
- internal static IServiceProvider Provider => _serviceProvider;
- private static ServiceProvider _serviceProvider = null!;
-
- [OneTimeSetUp]
- public void RunBeforeAnyTests()
- {
- var services = new ServiceCollection();
-
- services.AddLogging(x => x.AddNunitLogging());
- services.RegisterSqlContainer();
- services.AddScoped();
- services.RegisterMigrationInitializer();
- _serviceProvider = services.BuildServiceProvider();
- }
-
- [OneTimeTearDown]
- public async Task RunAfterAnyTests()
- {
- await _serviceProvider.DisposeAsync();
- }
-}
diff --git a/Tests/CleanAspCore.Api.Tests/GlobalUsings.cs b/Tests/CleanAspCore.Api.Tests/GlobalUsings.cs
index 239820a..39b7825 100644
--- a/Tests/CleanAspCore.Api.Tests/GlobalUsings.cs
+++ b/Tests/CleanAspCore.Api.Tests/GlobalUsings.cs
@@ -5,4 +5,3 @@
global using CleanAspCore.Api.TestUtils;
global using CleanAspCore.Api.TestUtils.Fakers;
global using FluentAssertions;
-global using NUnit.Framework;
diff --git a/Tests/CleanAspCore.Api.Tests/TUnitStartup.cs b/Tests/CleanAspCore.Api.Tests/TUnitStartup.cs
new file mode 100644
index 0000000..7576669
--- /dev/null
+++ b/Tests/CleanAspCore.Api.Tests/TUnitStartup.cs
@@ -0,0 +1,35 @@
+using CleanAspCore.Api.Tests;
+using CleanAspCore.Data;
+using CleanAspCore.TestUtils.DataBaseSetup;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using TUnit.Core.Interfaces;
+
+[assembly: ClassConstructor]
+[assembly: ExcludeFromCodeCoverage]
+
+namespace CleanAspCore.Api.Tests;
+
+public class DependencyInjectionClassConstructor : IClassConstructor, ITestEndEventReceiver
+{
+ private static readonly IServiceProvider _serviceProvider = CreateServiceProvider();
+
+ private AsyncServiceScope _scope;
+
+ public T Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(ClassConstructorMetadata classConstructorMetadata)
+ where T : class
+ {
+ _scope = _serviceProvider.CreateAsyncScope();
+ return ActivatorUtilities.GetServiceOrCreateInstance(_scope.ServiceProvider);
+ }
+
+ public ValueTask OnTestEnd(TestContext testContext) => _scope.DisposeAsync();
+
+ private static ServiceProvider CreateServiceProvider() =>
+ new ServiceCollection()
+ .AddLogging(x => x.AddConsole())
+ .RegisterSqlContainer()
+ .RegisterMigrationInitializer()
+ .AddScoped()
+ .BuildServiceProvider();
+}
diff --git a/Tests/CleanAspCore.Api.Tests/TestSetup/TestBase.cs b/Tests/CleanAspCore.Api.Tests/TestSetup/TestBase.cs
deleted file mode 100644
index 2edd249..0000000
--- a/Tests/CleanAspCore.Api.Tests/TestSetup/TestBase.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-
-namespace CleanAspCore.Api.Tests.TestSetup;
-
-internal abstract class TestBase
-{
-#pragma warning disable NUnit1032
- protected TestWebApi Sut { get; private set; } = null!;
-#pragma warning restore NUnit1032
-
- private AsyncServiceScope _scope;
-
- [SetUp]
- public void BeforeTestCase()
- {
- _scope = GlobalSetup.Provider.CreateAsyncScope();
- Sut = _scope.ServiceProvider.GetRequiredService();
- }
-
- [TearDown]
- public async Task AfterTestCase()
- {
- await _scope.DisposeAsync();
- }
-}
diff --git a/Tests/CleanAspCore.Api.Tests/TestSetup/TestWebApi.cs b/Tests/CleanAspCore.Api.Tests/TestSetup/TestWebApi.cs
index 5cff326..0b6e640 100644
--- a/Tests/CleanAspCore.Api.Tests/TestSetup/TestWebApi.cs
+++ b/Tests/CleanAspCore.Api.Tests/TestSetup/TestWebApi.cs
@@ -13,7 +13,7 @@
namespace CleanAspCore.Api.Tests.TestSetup;
-internal sealed class TestWebApi : WebApplicationFactory
+public sealed class TestWebApi : WebApplicationFactory
{
private readonly PooledDatabase _pooledDatabase;
private readonly ILoggerProvider _loggerProvider;
diff --git a/Tests/CleanAspCore.TestUtils/CleanAspCore.TestUtils.csproj b/Tests/CleanAspCore.TestUtils/CleanAspCore.TestUtils.csproj
index dfa0be1..2f64fa1 100644
--- a/Tests/CleanAspCore.TestUtils/CleanAspCore.TestUtils.csproj
+++ b/Tests/CleanAspCore.TestUtils/CleanAspCore.TestUtils.csproj
@@ -4,7 +4,6 @@
-
diff --git a/Tests/CleanAspCore.TestUtils/DataBaseSetup/ServiceCollectionExtensions.cs b/Tests/CleanAspCore.TestUtils/DataBaseSetup/ServiceCollectionExtensions.cs
index 30534ed..67b1ca4 100644
--- a/Tests/CleanAspCore.TestUtils/DataBaseSetup/ServiceCollectionExtensions.cs
+++ b/Tests/CleanAspCore.TestUtils/DataBaseSetup/ServiceCollectionExtensions.cs
@@ -13,7 +13,7 @@ public static void RegisterSharedDatabaseServices(this IServiceCollection servic
services.AddSingleton();
}
- public static void RegisterSqlContainer(this IServiceCollection services)
+ public static IServiceCollection RegisterSqlContainer(this IServiceCollection services)
{
services.RegisterSharedDatabaseServices();
services.AddTransient(c => new RespawnerOptions { DbAdapter = DbAdapter.SqlServer });
@@ -26,11 +26,14 @@ public static void RegisterSqlContainer(this IServiceCollection services)
container.StartAsync().RunSynchronouslyWithoutSynchronizationContext();
services.AddSingleton(container);
+
+ return services;
}
- public static void RegisterMigrationInitializer(this IServiceCollection services)
+ public static IServiceCollection RegisterMigrationInitializer(this IServiceCollection services)
where TContext : DbContext, new()
{
services.AddSingleton>();
+ return services;
}
}
diff --git a/Tests/CleanAspCore.TestUtils/Logging/LoggingBuilderExtensions.cs b/Tests/CleanAspCore.TestUtils/Logging/LoggingBuilderExtensions.cs
deleted file mode 100644
index c47128f..0000000
--- a/Tests/CleanAspCore.TestUtils/Logging/LoggingBuilderExtensions.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace CleanAspCore.Api.TestUtils.Logging;
-
-public static class LoggingBuilderExtensions
-{
- public static ILoggingBuilder AddNunitLogging(this ILoggingBuilder services)
- {
-#pragma warning disable CA2000
- services.AddProvider(new NunitLoggerProvider());
-#pragma warning restore CA2000
- return services;
- }
-}
diff --git a/Tests/CleanAspCore.TestUtils/Logging/NunitLogger.cs b/Tests/CleanAspCore.TestUtils/Logging/NunitLogger.cs
deleted file mode 100644
index 22290b1..0000000
--- a/Tests/CleanAspCore.TestUtils/Logging/NunitLogger.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace CleanAspCore.Api.TestUtils.Logging;
-
-internal sealed class NunitLogger(TextWriter output, string name) : ILogger, IDisposable
-{
- public IDisposable? BeginScope(TState state) where TState : notnull => this;
-
- public bool IsEnabled(LogLevel logLevel) => true;
-
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter)
- {
- output.WriteLine($"[{DateTime.Now}] {logLevel}: {name}[{eventId.Id}] => {formatter(state, exception)}");
- }
-
- public void Dispose() { }
-}
diff --git a/Tests/CleanAspCore.TestUtils/Logging/NunitLoggerProvider.cs b/Tests/CleanAspCore.TestUtils/Logging/NunitLoggerProvider.cs
deleted file mode 100644
index e498f46..0000000
--- a/Tests/CleanAspCore.TestUtils/Logging/NunitLoggerProvider.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Microsoft.Extensions.Logging;
-using NUnit.Framework;
-
-namespace CleanAspCore.Api.TestUtils.Logging;
-
-internal sealed class NunitLoggerProvider : ILoggerProvider
-{
- public ILogger CreateLogger(string categoryName)
- {
- return new NunitLogger(TestContext.Out, categoryName);
- }
-
- public void Dispose()
- {
- }
-}