diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs
index 45dbcbc..a0f26c7 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs
@@ -1,13 +1,13 @@
-using Faura.Infrastructure.IntegrationTesting.Constants;
-using Faura.Infrastructure.IntegrationTesting.Seeders;
+namespace Faura.Infrastructure.IntegrationTesting.Factory;
+
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Faura.Infrastructure.IntegrationTesting.Constants;
+using Faura.Infrastructure.IntegrationTesting.Seeders;
using Xunit;
-namespace Faura.Infrastructure.IntegrationTesting.Factory;
-
///
/// Base factory for integration tests with container setup and service customization.
///
@@ -16,47 +16,67 @@ public abstract class BaseWebApplicationFactory
IAsyncLifetime
where TEntryPoint : class
{
- ///
- /// Final configuration used during the test run.
- ///
- protected IConfiguration? Configuration;
+ private static readonly SemaphoreSlim _initializationLock = new(1, 1);
+ private static bool _isInitialized;
+ private static IConfiguration? _sharedConfiguration;
+
+ protected IConfiguration? Configuration { get; set; }
public async Task InitializeAsync()
{
- Environment.SetEnvironmentVariable(
- "ASPNETCORE_ENVIRONMENT",
- IntegrationTestConstants.Environment
- );
+ await _initializationLock.WaitAsync();
+ try
+ {
+ if (!_isInitialized)
+ {
+ Environment.SetEnvironmentVariable(
+ "ASPNETCORE_ENVIRONMENT",
+ IntegrationTestConstants.Environment);
- var testProjectPath = Directory.GetCurrentDirectory();
- var settingsFile = Path.Combine(
- testProjectPath,
- $"appsettings.{IntegrationTestConstants.Environment}.json"
- );
+ var testProjectPath = Directory.GetCurrentDirectory();
+ var settingsFile = Path.Combine(
+ testProjectPath,
+ $"appsettings.{IntegrationTestConstants.Environment}.json");
- var configBuilder = new ConfigurationBuilder()
- .AddJsonFile(settingsFile, optional: false)
- .AddEnvironmentVariables();
+ var configBuilder = new ConfigurationBuilder()
+ .AddJsonFile(settingsFile, optional: false)
+ .AddEnvironmentVariables();
- await ConfigureConfigurationAsync(configBuilder);
+ await ConfigureConfigurationAsync(configBuilder);
+
+ var baseConfig = configBuilder.Build();
+ _sharedConfiguration = await ConfigureTestContainersAsync(baseConfig);
+
+ _isInitialized = true;
+ }
- var baseConfig = configBuilder.Build();
- Configuration = await ConfigureTestContainersAsync(baseConfig);
+ Configuration = _sharedConfiguration;
+ }
+ finally
+ {
+ _initializationLock.Release();
+ }
}
- public virtual Task DisposeAsync() => Task.CompletedTask;
+ public override async ValueTask DisposeAsync()
+ {
+ await base.DisposeAsync();
+ GC.SuppressFinalize(this);
+ }
+
+ async Task IAsyncLifetime.DisposeAsync() => await DisposeAsync();
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment(IntegrationTestConstants.Environment);
- builder.ConfigureAppConfiguration(
- (_, config) =>
- {
- config.Sources.Clear();
- config.AddConfiguration(Configuration!);
- }
- );
+ builder
+ .UseConfiguration(Configuration!)
+ .ConfigureAppConfiguration(
+ (_, config) =>
+ {
+ config.AddConfiguration(Configuration!);
+ });
builder.ConfigureServices(services =>
{
@@ -65,7 +85,10 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
using var provider = services.BuildServiceProvider(validateScopes: true);
using var scope = provider.CreateScope();
- RunSeedersAsync(scope.ServiceProvider).GetAwaiter().GetResult();
+
+ BaseWebApplicationFactory.RunSeedersAsync(scope.ServiceProvider)
+ .GetAwaiter()
+ .GetResult();
});
}
@@ -79,26 +102,27 @@ protected virtual Task ConfigureConfigurationAsync(IConfigurationBuilder builder
/// Starts containers and returns updated configuration (e.g., with connection strings).
///
protected virtual Task ConfigureTestContainersAsync(
- IConfiguration configuration
- ) => Task.FromResult(configuration);
+ IConfiguration configuration) => Task.FromResult(configuration);
///
/// Registers test-specific or mocked services.
///
protected virtual void ConfigureTestServices(
IServiceCollection services,
- IConfiguration configuration
- ) { }
+ IConfiguration configuration)
+ {
+ }
///
/// Registers database context and ensures schema is created.
///
protected virtual void ConfigureTestDatabase(
IServiceCollection services,
- IConfiguration configuration
- ) { }
+ IConfiguration configuration)
+ {
+ }
- private async Task RunSeedersAsync(IServiceProvider serviceProvider)
+ private static async Task RunSeedersAsync(IServiceProvider serviceProvider)
{
foreach (var seeder in serviceProvider.GetServices())
{
@@ -113,4 +137,4 @@ private async Task RunSeedersAsync(IServiceProvider serviceProvider)
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj
index 6d62275..9864a52 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj
@@ -1,45 +1,25 @@
-
net8.0
enable
enable
- Faura Integration Testing
- https://github.com/JosepFe/faura/blob/master/LICENSE
+ Faura Integration Testing Library
git
faura;testing;integrationTesting
- README.md
NET 8.0+ compatibility version
- LICENSE
- True
- $(NoWarn);NETSDK1206;1701;1702;NU1608;CA1822
-
-
+
+
+
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
- True
- \
-
-
- True
- \
-
+
+ **/**/*.cs
+
-
-
+
\ No newline at end of file
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/ContainerOptions.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/ContainerOptions.cs
index d9b65db..652e97b 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/ContainerOptions.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/ContainerOptions.cs
@@ -4,7 +4,7 @@ public class ContainerOptions
{
public string Image { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
- public int Port { get; set; }
+ public int? Port { get; set; }
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string Database { get; set; } = string.Empty;
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/TestContainerOptions.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/TestContainerOptions.cs
index a161db2..7d0d3f8 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/TestContainerOptions.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Options/TestContainerOptions.cs
@@ -1,9 +1,7 @@
-namespace Faura.Infrastructure.IntegrationTesting.Options;
+namespace Faura.Infrastructure.IntegrationTesting.Options;
public class TestContainerOptions
{
- public ContainerOptions Mongo { get; set; } = new();
- public ContainerOptions Redis { get; set; } = new();
+ public ContainerOptions SqlServer { get; set; } = new ();
public ContainerOptions Postgres { get; set; } = new();
- public ContainerOptions SqlServer { get; set; } = new();
}
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs
index 76b270c..dc483c6 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs
@@ -1,7 +1,7 @@
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
+namespace Faura.Infrastructure.IntegrationTesting.Seeders;
-namespace Faura.Infrastructure.IntegrationTesting.Seeders;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
public abstract class TestDataSeeder : ITestDataSeeder
where TContext : DbContext
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs
index b4b40eb..214237f 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs
@@ -1,11 +1,13 @@
using Faura.Infrastructure.IntegrationTesting.Options;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants;
using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
public class MongoContainerConfiguration : ITestContainerConfiguration
{
+ private const string DefaultImage = "mongo:7-jammy";
+ private const int MongoInternalPort = 27017;
+
private readonly ContainerOptions _options;
public MongoContainerConfiguration(ContainerOptions options)
@@ -15,17 +17,44 @@ public MongoContainerConfiguration(ContainerOptions options)
public string Image =>
string.IsNullOrWhiteSpace(_options.Image)
- ? ContainerDefaultsConstants.Images.Mongo
+ ? DefaultImage
: _options.Image;
- public int Port => _options.Port != 0 ? _options.Port : ContainerDefaultsConstants.Ports.Mongo;
+ public int? Port => _options.Port;
+
+ public int InternalPort => MongoInternalPort;
public string Username => _options.Username ?? string.Empty;
+
public string Password => _options.Password ?? string.Empty;
+
public string Database => _options.Database ?? "test";
- public Dictionary GetEnvironmentVariables() => new();
+ public Dictionary GetEnvironmentVariables()
+ {
+ var env = new Dictionary();
+
+ if (!string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password))
+ {
+ env["MONGO_INITDB_ROOT_USERNAME"] = Username;
+ env["MONGO_INITDB_ROOT_PASSWORD"] = Password;
+ }
- public string BuildConnectionString(int mappedPort) =>
- $"mongodb://localhost:{mappedPort}/{Database}";
-}
+ if (!string.IsNullOrWhiteSpace(Database))
+ {
+ env["MONGO_INITDB_DATABASE"] = Database;
+ }
+
+ return env;
+ }
+
+ public string BuildConnectionString(string host, int mappedPort)
+ {
+ if (!string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password))
+ {
+ return $"mongodb://{Username}:{Password}@{host}:{mappedPort}/{Database}?authSource=admin";
+ }
+
+ return $"mongodb://{host}:{mappedPort}/{Database}";
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs
index 05ce5f2..49ffd04 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs
@@ -1,11 +1,13 @@
-using Faura.Infrastructure.IntegrationTesting.Options;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
+namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
-namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
+using Faura.Infrastructure.IntegrationTesting.Options;
+using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
public class PostgresContainerConfiguration : ITestContainerConfiguration
{
+ private const string DefaultImage = "postgres:15-alpine";
+ private const int PostgresInternalPort = 5432;
+
private readonly ContainerOptions _options;
public PostgresContainerConfiguration(ContainerOptions options)
@@ -15,11 +17,12 @@ public PostgresContainerConfiguration(ContainerOptions options)
public string Image =>
string.IsNullOrWhiteSpace(_options.Image)
- ? ContainerDefaultsConstants.Images.Postgres
+ ? DefaultImage
: _options.Image;
- public int Port =>
- _options.Port != 0 ? _options.Port : ContainerDefaultsConstants.Ports.Postgres;
+ public int? Port => _options.Port;
+
+ public int InternalPort => PostgresInternalPort;
public string Username => _options.Username ?? "postgres";
public string Password => _options.Password ?? "postgres";
@@ -33,6 +36,6 @@ public Dictionary GetEnvironmentVariables() =>
["POSTGRES_DB"] = Database,
};
- public string BuildConnectionString(int mappedPort) =>
- $"Host=localhost;Port={mappedPort};Username={Username};Password={Password};Database={Database}";
+ public string BuildConnectionString(string host, int mappedPort) =>
+ $"Host={host};Port={mappedPort};Username={Username};Password={Password};Database={Database}";
}
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs
index c123cb0..33712e6 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs
@@ -1,11 +1,13 @@
using Faura.Infrastructure.IntegrationTesting.Options;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants;
using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
public class RedisContainerConfiguration : ITestContainerConfiguration
{
+ private const string DefaultImage = "redis:7-alpine";
+ private const int RedisInternalPort = 6379;
+
private readonly ContainerOptions _options;
public RedisContainerConfiguration(ContainerOptions options)
@@ -15,16 +17,45 @@ public RedisContainerConfiguration(ContainerOptions options)
public string Image =>
string.IsNullOrWhiteSpace(_options.Image)
- ? ContainerDefaultsConstants.Images.Redis
+ ? DefaultImage
: _options.Image;
- public int Port => _options.Port != 0 ? _options.Port : ContainerDefaultsConstants.Ports.Redis;
+ public int? Port => _options.Port;
+
+ public int InternalPort => RedisInternalPort;
public string Username => _options.Username ?? string.Empty;
+
public string Password => _options.Password ?? string.Empty;
- public string Database => _options.Database ?? string.Empty;
- public Dictionary GetEnvironmentVariables() => new();
+ public string Database => _options.Database ?? "0";
- public string BuildConnectionString(int mappedPort) => $"localhost:{mappedPort}";
-}
+ public Dictionary GetEnvironmentVariables()
+ {
+ var env = new Dictionary();
+
+ if (!string.IsNullOrWhiteSpace(Password))
+ {
+ env["REDIS_PASSWORD"] = Password;
+ }
+
+ return env;
+ }
+
+ public string BuildConnectionString(string host, int mappedPort)
+ {
+ var connectionString = $"{host}:{mappedPort}";
+
+ if (!string.IsNullOrWhiteSpace(Password))
+ {
+ connectionString += $",password={Password}";
+ }
+
+ if (!string.IsNullOrWhiteSpace(Database) && Database != "0")
+ {
+ connectionString += $",defaultDatabase={Database}";
+ }
+
+ return connectionString;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs
index 3c3efb4..613d675 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs
@@ -1,33 +1,36 @@
-using Faura.Infrastructure.IntegrationTesting.Options;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
-
namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
+using Faura.Infrastructure.IntegrationTesting.Options;
+using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
+
public class SqlServerContainerConfiguration : ITestContainerConfiguration
{
+ private const string DefaultImage = "mcr.microsoft.com/mssql/server:2022-lts";
+ private const int SqlServerInternalPort = 1433;
private readonly ContainerOptions _options;
- public SqlServerContainerConfiguration(ContainerOptions options)
- {
- _options = options;
- }
+ public SqlServerContainerConfiguration(ContainerOptions options) => _options = options;
public string Image =>
string.IsNullOrWhiteSpace(_options.Image)
- ? ContainerDefaultsConstants.Images.SqlServer
+ ? DefaultImage
: _options.Image;
- public int Port =>
- _options.Port != 0 ? _options.Port : ContainerDefaultsConstants.Ports.SqlServer;
+ public int? Port =>_options.Port;
+ public int InternalPort => SqlServerInternalPort;
public string Username => _options.Username ?? "sa";
public string Password => _options.Password ?? "Your_strong_password123!";
public string Database => _options.Database ?? "TestDb";
public Dictionary GetEnvironmentVariables() =>
- new() { ["ACCEPT_EULA"] = "Y", ["SA_PASSWORD"] = Password };
-
- public string BuildConnectionString(int mappedPort) =>
- $"Server=localhost,{mappedPort};Database={Database};User Id={Username};Password={Password};TrustServerCertificate=True";
+ new()
+ {
+ ["ACCEPT_EULA"] = "Y",
+ ["SA_PASSWORD"] = Password,
+ ["MSSQL_PID"] = "Developer",
+ };
+
+ public string BuildConnectionString(string host, int mappedPort) =>
+ $"Server={host},{mappedPort};Database={Database};User Id={Username};Password={Password};TrustServerCertificate=True";
}
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Constants/ContainerDefaultsConstants.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Constants/ContainerDefaultsConstants.cs
deleted file mode 100644
index 448ed09..0000000
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Constants/ContainerDefaultsConstants.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Constants;
-
-public static class ContainerDefaultsConstants
-{
- public static class Images
- {
- public const string Mongo = "mongo:6";
- public const string Redis = "redis:7";
- public const string Postgres = "postgres:15-alpine";
- public const string SqlServer = "mcr.microsoft.com/mssql/server:2022-lts";
- }
-
- public static class Ports
- {
- public const int Mongo = 27017;
- public const int Redis = 6379;
- public const int Postgres = 5432;
- public const int SqlServer = 1433;
- }
-}
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/ITestContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/ITestContainerConfiguration.cs
index ef727fc..c2bb0d1 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/ITestContainerConfiguration.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/ITestContainerConfiguration.cs
@@ -3,11 +3,12 @@
public interface ITestContainerConfiguration
{
string Image { get; }
- int Port { get; }
+ int? Port { get; }
+ int InternalPort { get; }
string Username { get; }
string Password { get; }
string Database { get; }
Dictionary GetEnvironmentVariables();
- string BuildConnectionString(int mappedPort);
+ string BuildConnectionString(string host, int mappedPort);
}
diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs
index 0232f37..51ae0d4 100644
--- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs
+++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs
@@ -1,16 +1,14 @@
-using DotNet.Testcontainers.Builders;
-using DotNet.Testcontainers.Containers;
-
namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
+using DotNet.Testcontainers.Builders;
+using DotNet.Testcontainers.Containers;
+
public class TestContainerInstance
where T : ITestContainerConfiguration
{
private readonly T _config;
private readonly IContainer _container;
- public string ConnectionString { get; private set; } = string.Empty;
-
public TestContainerInstance(T config)
{
_config = config;
@@ -19,7 +17,13 @@ public TestContainerInstance(T config)
.WithImage(_config.Image)
.WithName($"testcontainer-{Guid.NewGuid():N}")
.WithCleanUp(true)
- .WithPortBinding(_config.Port, true);
+ .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(_config.InternalPort));
+
+ builder = _config.Port switch
+ {
+ null or 0 => builder.WithPortBinding(_config.InternalPort, true),
+ var port => builder.WithPortBinding(port.Value, _config.InternalPort)
+ };
foreach (var kvp in _config.GetEnvironmentVariables())
{
@@ -29,11 +33,14 @@ public TestContainerInstance(T config)
_container = builder.Build();
}
+ public string ConnectionString { get; private set; } = string.Empty;
+
public async Task StartAsync()
{
await _container.StartAsync();
- var mappedPort = _container.GetMappedPublicPort(_config.Port);
- ConnectionString = _config.BuildConnectionString(mappedPort);
+ var host = _container.Hostname;
+ var mappedPort = _container.GetMappedPublicPort(_config.InternalPort);
+ ConnectionString = _config.BuildConnectionString(host, mappedPort);
}
public Task StopAsync() => _container.StopAsync();
diff --git a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs b/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs
index 7e37e39..d836e97 100644
--- a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs
+++ b/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs
@@ -1,33 +1,21 @@
-using DotNet.Testcontainers.Containers;
-using Faura.Infrastructure.IntegrationTesting.Factory;
-using Faura.Infrastructure.IntegrationTesting.Options;
-using Faura.Infrastructure.IntegrationTesting.Seeders;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
-using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
-using Faura.Infrastructure.UnitOfWork.Common;
+using Faura.Infrastructure.UnitOfWork.Common;
using Faura.Infrastructure.UnitOfWork.Enums;
using Faura.IntegrationTest.Seeders;
+using Faura.WebAPI.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
-using YourNamespace.Data;
+using Faura.Infrastructure.IntegrationTesting.Factory;
+using Faura.Infrastructure.IntegrationTesting.Options;
+using Faura.Infrastructure.IntegrationTesting.Seeders;
+using Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations;
+using Faura.Infrastructure.IntegrationTesting.TestContainers.Core;
namespace Faura.IntegrationTest.Configuration;
-public class CustomWebApplicationFactory : BaseWebApplicationFactory
- where TEntryPoint : class
+public class CustomWebApplicationFactory : BaseWebApplicationFactory
{
- private IContainer? _postgresContainer;
-
- public override async Task DisposeAsync()
- {
- if (_postgresContainer is not null)
- {
- await _postgresContainer.StopAsync();
- }
- }
-
protected override async Task ConfigureTestContainersAsync(
IConfiguration configuration
)
diff --git a/src/Templates/Faura.IntegrationTest/Configuration/IntegrationTestBase.cs b/src/Templates/Faura.IntegrationTest/Configuration/IntegrationTestBase.cs
new file mode 100644
index 0000000..54c647a
--- /dev/null
+++ b/src/Templates/Faura.IntegrationTest/Configuration/IntegrationTestBase.cs
@@ -0,0 +1,38 @@
+namespace Faura.IntegrationTest.Configuration;
+
+using Faura.WebAPI.Domain;
+using Faura.WebAPI.Infrastructure.Persistence;
+using Microsoft.Extensions.DependencyInjection;
+
+public abstract class IntegrationTestBase : IClassFixture, IAsyncLifetime
+{
+ protected readonly HttpClient Client;
+ private readonly IServiceScope _scope;
+ protected readonly EmployeeDbContext DbContext;
+ protected readonly IEmployeeRepository EmployeeRepository;
+
+ protected IntegrationTestBase(CustomWebApplicationFactory factory)
+ {
+ Client = factory.CreateClient();
+ _scope = factory.Services.CreateScope();
+ DbContext = _scope.ServiceProvider.GetRequiredService();
+ EmployeeRepository = _scope.ServiceProvider.GetRequiredService();
+ }
+
+ public async Task InitializeAsync()
+ {
+ await DbContext.Database.EnsureCreatedAsync();
+ await SeedTestDataAsync();
+ }
+
+ protected virtual async Task SeedTestDataAsync()
+ {
+ await Task.CompletedTask;
+ }
+
+ public Task DisposeAsync()
+ {
+ _scope?.Dispose();
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj b/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj
index 57cd07a..20f5ae8 100644
--- a/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj
+++ b/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj
@@ -1,33 +1,34 @@
-
+
+
+ net8.0
+ enable
+ enable
+ false
+ true
+
-
- net8.0
- enable
- enable
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
- false
- true
-
+
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- PreserveNewest
-
-
-
-
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs b/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs
index fc22111..65855c8 100644
--- a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs
+++ b/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs
@@ -1,8 +1,8 @@
-using Faura.Infrastructure.IntegrationTesting.Seeders;
-using Faura.WebAPI.Domain;
+using Faura.WebAPI.Domain;
using Faura.WebAPI.Domain.Entities;
+using Faura.WebAPI.Infrastructure.Persistence;
using Microsoft.Extensions.DependencyInjection;
-using YourNamespace.Data;
+using Faura.Infrastructure.IntegrationTesting.Seeders;
namespace Faura.IntegrationTest.Seeders;
diff --git a/src/Templates/Faura.IntegrationTest/UseCases/EmployeeTests.cs b/src/Templates/Faura.IntegrationTest/UseCases/EmployeeTests.cs
new file mode 100644
index 0000000..6b25b0a
--- /dev/null
+++ b/src/Templates/Faura.IntegrationTest/UseCases/EmployeeTests.cs
@@ -0,0 +1,71 @@
+using Faura.IntegrationTest.Configuration;
+using Faura.WebAPI.Controllers;
+using Faura.WebAPI.Domain.Entities;
+using System.Net.Http.Json;
+namespace Faura.IntegrationTest.UseCases;
+public class EmployeeTests : IntegrationTestBase
+{
+ public EmployeeTests(CustomWebApplicationFactory factory) : base(factory) { }
+
+ protected override async Task SeedTestDataAsync()
+ {
+ await EmployeeRepository.CreateAsync(
+ new Employee("Custom", "Seed", "custom@example.com")
+ );
+ await EmployeeRepository.CreateAsync(
+ new Employee("Another", "User", "another@example.com")
+ );
+ }
+
+ [Fact]
+ public async Task Should_Return_Employees()
+ {
+ // Act
+ var response = await Client.GetAsync("/Employee");
+ // Assert
+ response.EnsureSuccessStatusCode();
+ var data = await response.Content.ReadFromJsonAsync>();
+ Assert.NotNull(data);
+ Assert.NotEmpty(data);
+ }
+
+ [Fact]
+ public async Task Should_Create_Employee()
+ {
+ // Arrange
+ var request = new CreateEmployeeRequest("John", "Doe", "john.doe@example.com");
+ // Act
+ var response = await Client.PostAsJsonAsync("/Employee", request);
+ // Assert
+ response.EnsureSuccessStatusCode();
+ var createdEmployee = await response.Content.ReadFromJsonAsync();
+ Assert.NotNull(createdEmployee);
+ Assert.Equal("John", createdEmployee.FirstName);
+ Assert.Equal("Doe", createdEmployee.LastName);
+ Assert.Equal("john.doe@example.com", createdEmployee.Email);
+ }
+
+ [Fact]
+ public async Task Should_Create_Multiple_Employees_With_Transaction()
+ {
+ // Arrange
+ var request = new CreateMultipleEmployeesRequest(
+ "Jane",
+ "Smith",
+ "jane.smith@example.com",
+ "Bob",
+ "Johnson",
+ "bob.johnson@example.com"
+ );
+ // Act
+ var response = await Client.PostAsJsonAsync("/Employee/multiple", request);
+ // Assert
+ response.EnsureSuccessStatusCode();
+ var createdEmployees = await response.Content.ReadFromJsonAsync>();
+ Assert.NotNull(createdEmployees);
+ Assert.Equal(2, createdEmployees.Count());
+ var employeeList = createdEmployees.ToList();
+ Assert.Equal("Jane", employeeList[0].FirstName);
+ Assert.Equal("Bob", employeeList[1].FirstName);
+ }
+}
\ No newline at end of file
diff --git a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs b/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs
deleted file mode 100644
index 72f9e31..0000000
--- a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Net.Http.Json;
-using Faura.IntegrationTest.Configuration;
-using Faura.WebAPI.Controllers;
-
-namespace Faura.IntegrationTest.UseCases;
-
-public class WeatherForecastTests : IClassFixture>
-{
- private readonly HttpClient _client;
-
- public WeatherForecastTests(CustomWebApplicationFactory factory)
- {
- _client = factory.CreateClient();
- }
-
- [Fact]
- public async Task Should_Return_WeatherForecast()
- {
- // Act
- var response = await _client.GetAsync("/WeatherForecast");
-
- // Assert
- response.EnsureSuccessStatusCode();
-
- var data = await response.Content.ReadFromJsonAsync>();
- Assert.NotNull(data);
- Assert.NotEmpty(data);
- }
-}
diff --git a/src/Templates/Faura.IntegrationTest/appsettings.Test.json b/src/Templates/Faura.IntegrationTest/appsettings.Test.json
index 282e307..3406c6e 100644
--- a/src/Templates/Faura.IntegrationTest/appsettings.Test.json
+++ b/src/Templates/Faura.IntegrationTest/appsettings.Test.json
@@ -19,7 +19,7 @@
"Containers": {
"Postgres": {
"Image": "postgres:15-alpine",
- "Port": 5432,
+ "Port": 5233,
"Username": "testuser",
"Password": "testpass",
"Database": "testdb"
diff --git a/src/Templates/Faura.WebAPI/Application/EmployeeService.cs b/src/Templates/Faura.WebAPI/Application/EmployeeService.cs
new file mode 100644
index 0000000..06b8e31
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Application/EmployeeService.cs
@@ -0,0 +1,71 @@
+using Faura.Infrastructure.Logger.Extensions;
+using Faura.WebAPI.Domain;
+using Faura.WebAPI.Domain.Entities;
+using Faura.WebAPI.Infrastructure.Persistence;
+
+namespace Faura.WebAPI.Application;
+
+public class EmployeeService : IEmployeeService
+{
+ private readonly ILogger _logger;
+ private readonly IEmployeeRepository _employeeRepository;
+ private readonly IEmployeeUoW _uoW;
+
+ public EmployeeService(
+ ILogger logger,
+ IEmployeeRepository employeeRepository,
+ IEmployeeUoW uoW
+ )
+ {
+ _logger = logger;
+ _employeeRepository = employeeRepository;
+ _uoW = uoW;
+ }
+
+ public async Task> GetEmployeesAsync()
+ {
+ _logger.LogFauraInformation("Starting Get Employees");
+ return await _employeeRepository.GetAsync();
+ }
+
+ public async Task CreateEmployeeAsync(string firstName, string lastName, string email)
+ {
+ _logger.LogFauraInformation($"Creating employee: {firstName} {lastName}");
+ var employee = new Employee(firstName, lastName, email);
+ var result = await _employeeRepository.CreateAsync(employee);
+ return result;
+ }
+
+ public async Task> CreateMultipleEmployeesWithTransactionAsync(
+ string firstName1,
+ string lastName1,
+ string email1,
+ string firstName2,
+ string lastName2,
+ string email2
+ )
+ {
+ _logger.LogFauraInformation("Creating multiple employees with transaction");
+
+ var transaction = await _uoW.GetDbTransaction();
+
+ var employee1 = await _employeeRepository.CreateAsync(
+ new Employee(firstName1, lastName1, email1),
+ false,
+ false
+ );
+
+ var employee2 = await _employeeRepository.CreateAsync(
+ new Employee(firstName2, lastName2, email2),
+ false,
+ false
+ );
+
+ // send event 1
+ // send event 2
+
+ await _uoW.CommitTransaction(transaction);
+
+ return [employee1, employee2];
+ }
+}
diff --git a/src/Templates/Faura.WebAPI/Application/IEmployeeService.cs b/src/Templates/Faura.WebAPI/Application/IEmployeeService.cs
new file mode 100644
index 0000000..0bba349
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Application/IEmployeeService.cs
@@ -0,0 +1,17 @@
+using Faura.WebAPI.Domain.Entities;
+
+namespace Faura.WebAPI.Application;
+
+public interface IEmployeeService
+{
+ Task> GetEmployeesAsync();
+ Task CreateEmployeeAsync(string firstName, string lastName, string email);
+ Task> CreateMultipleEmployeesWithTransactionAsync(
+ string firstName1,
+ string lastName1,
+ string email1,
+ string firstName2,
+ string lastName2,
+ string email2
+ );
+}
diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs
index 562e81a..fadbcac 100644
--- a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs
+++ b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs
@@ -1,43 +1,15 @@
-using Faura.Infrastructure.UnitOfWork;
-using Faura.Infrastructure.UnitOfWork.Common;
-using Faura.Infrastructure.UnitOfWork.Enums;
-using Faura.WebAPI.Domain;
+using Faura.WebAPI.Application;
using Faura.WebAPI.Infrastructure.Persistence;
-using YourNamespace.Data;
namespace Faura.WebAPI.Bootstrappers;
public static class ApplicationBootstrapper
{
public static WebApplicationBuilder RegisterApplicationDependencies(
- this WebApplicationBuilder builder
- )
+ this WebApplicationBuilder builder)
{
- builder.Services.SetupDatabase(builder.Configuration);
-
- builder.Services.AddScoped();
+ builder.Services.AddScoped();
builder.Services.AddScoped();
return builder;
}
-
- ///
- /// Setup here your database connections.
- ///
- ///
- ///
- private static void SetupDatabase(
- this IServiceCollection services,
- IConfiguration configuration
- )
- {
- services.SetupUnitOfWork();
- services
- .ConfigureDatabase(
- configuration,
- "Employee",
- DatabaseType.PostgreSQL,
- ServiceLifetime.Scoped
- )
- .ConfigureAwait(false);
- }
}
diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/InfrastructureBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/InfrastructureBootstrapper.cs
new file mode 100644
index 0000000..a8b8b87
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Bootstrappers/InfrastructureBootstrapper.cs
@@ -0,0 +1,47 @@
+namespace Faura.WebAPI.Bootstrappers;
+
+using Faura.Infrastructure.UnitOfWork.Common;
+using Faura.Infrastructure.UnitOfWork.Enums;
+using Faura.WebAPI.Domain;
+using Faura.WebAPI.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+
+public static class InfrastructureBootstrapper
+{
+ public static IServiceCollection RegisterInfrastructureDependencies(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddDatabase(configuration);
+ services.AddRepositories();
+
+ return services;
+ }
+
+ public static async Task ConfigureInfrastructureAsync(this WebApplication app, IWebHostEnvironment env)
+ {
+ await MigrateDatabaseAsync(app, env);
+ return app;
+ }
+
+ private static async Task MigrateDatabaseAsync(WebApplication app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ using var scope = app.Services.CreateScope();
+ var dbContext = scope.ServiceProvider.GetRequiredService();
+ await dbContext.Database.MigrateAsync();
+ }
+ }
+
+ private static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.ConfigureDatabase(configuration, "Employee", DatabaseType.PostgreSQL);
+ return services;
+ }
+
+ private static IServiceCollection AddRepositories(this IServiceCollection services)
+ {
+ services.AddScoped();
+
+ return services;
+ }
+}
\ No newline at end of file
diff --git a/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs b/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs
new file mode 100644
index 0000000..b0b3ed9
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs
@@ -0,0 +1,59 @@
+using Faura.WebAPI.Application;
+using Faura.WebAPI.Domain.Entities;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Faura.WebAPI.Controllers;
+
+[ApiController]
+[Route("[controller]")]
+public class EmployeeController : ControllerBase
+{
+ private readonly IEmployeeService _employeeService;
+
+ public EmployeeController(IEmployeeService employeeService)
+ {
+ _employeeService = employeeService;
+ }
+
+ [HttpGet(Name = "GetEmployees")]
+ public async Task> Get()
+ {
+ return await _employeeService.GetEmployeesAsync();
+ }
+
+ [HttpPost(Name = "CreateEmployee")]
+ public async Task Create([FromBody] CreateEmployeeRequest request)
+ {
+ return await _employeeService.CreateEmployeeAsync(
+ request.FirstName,
+ request.LastName,
+ request.Email
+ );
+ }
+
+ [HttpPost("multiple", Name = "CreateMultipleEmployees")]
+ public async Task> CreateMultiple(
+ [FromBody] CreateMultipleEmployeesRequest request
+ )
+ {
+ return await _employeeService.CreateMultipleEmployeesWithTransactionAsync(
+ request.FirstName1,
+ request.LastName1,
+ request.Email1,
+ request.FirstName2,
+ request.LastName2,
+ request.Email2
+ );
+ }
+}
+
+public record CreateEmployeeRequest(string FirstName, string LastName, string Email);
+
+public record CreateMultipleEmployeesRequest(
+ string FirstName1,
+ string LastName1,
+ string Email1,
+ string FirstName2,
+ string LastName2,
+ string Email2
+);
diff --git a/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs b/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs
deleted file mode 100644
index 0664827..0000000
--- a/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Faura.WebAPI.Controllers;
-
-public class WeatherForecast
-{
- public DateOnly Date { get; set; }
-
- public int TemperatureC { get; set; }
-
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-
- public string? Summary { get; set; }
-}
diff --git a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs b/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs
deleted file mode 100644
index cc8e2df..0000000
--- a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using Faura.WebAPI.Domain;
-using Faura.WebAPI.Domain.Entities;
-using Faura.WebAPI.Infrastructure.Persistence;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Faura.WebAPI.Controllers;
-
-[ApiController]
-[Route("[controller]")]
-public class WeatherForecastController : ControllerBase
-{
- private static readonly string[] Summaries = new[]
- {
- "Freezing",
- "Bracing",
- "Chilly",
- "Cool",
- "Mild",
- "Warm",
- "Balmy",
- "Hot",
- "Sweltering",
- "Scorching",
- };
-
- private readonly ILogger _logger;
- private readonly IEmployeeRepository _employeeRepository;
- private readonly IEmployeeUoW _uoW;
-
- public WeatherForecastController(
- ILogger logger,
- IEmployeeRepository employeeRepository,
- IEmployeeUoW uoW
- )
- {
- _logger = logger;
- _employeeRepository = employeeRepository;
- _uoW = uoW;
- }
-
- [HttpGet(Name = "GetWeatherForecast")]
- public async Task> Get()
- {
- var res = await _employeeRepository.GetAsync();
-
- var transaction = await _uoW.GetDbTransaction();
-
- var res2 = await _employeeRepository.CreateAsync(
- new Employee("Josep", "Ferrandis", "algo@example.com"),
- false,
- false
- );
- var res3 = await _employeeRepository.CreateAsync(
- new Employee("Josep", "Ferrandis", "algo@example.com"),
- false,
- false
- );
-
- // send event 1
- // send event 2
-
- await _uoW.CommitTransaction(transaction);
-
- return Enumerable
- .Range(1, 5)
- .Select(index => new WeatherForecast
- {
- Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- TemperatureC = Random.Shared.Next(-20, 55),
- Summary = Summaries[Random.Shared.Next(Summaries.Length)],
- })
- .ToArray();
- }
-
- [HttpGet("Test")]
- [Authorize]
- public string GetTst()
- {
- return "Hola";
- }
-}
diff --git a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs b/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs
index 3e2038c..673ce98 100644
--- a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs
+++ b/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs
@@ -1,6 +1,6 @@
using Faura.Infrastructure.UnitOfWork.Repositories;
using Faura.WebAPI.Domain.Entities;
-using YourNamespace.Data;
+using Faura.WebAPI.Infrastructure.Persistence;
namespace Faura.WebAPI.Domain;
diff --git a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj
index ff18345..de8f301 100644
--- a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj
+++ b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj
@@ -9,6 +9,14 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -23,4 +31,8 @@
+
+
+
+
diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs
index 3a220b6..a9284f8 100644
--- a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs
+++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs
@@ -1,7 +1,7 @@
using Faura.WebAPI.Domain.Entities;
using Microsoft.EntityFrameworkCore;
-namespace YourNamespace.Data;
+namespace Faura.WebAPI.Infrastructure.Persistence;
public class EmployeeDbContext : DbContext
{
diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs
index 8658c6b..b7e1f46 100644
--- a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs
+++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs
@@ -1,5 +1,4 @@
using Faura.Infrastructure.UnitOfWork.UnitOfWork;
-using YourNamespace.Data;
namespace Faura.WebAPI.Infrastructure.Persistence;
diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.Designer.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.Designer.cs
new file mode 100644
index 0000000..61c4331
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.Designer.cs
@@ -0,0 +1,58 @@
+//
+using Faura.WebAPI.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Faura.WebAPI.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(EmployeeDbContext))]
+ [Migration("20251211113454_InitialCreate")]
+ partial class InitialCreate
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.14")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Faura.WebAPI.Domain.Entities.Employee", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("email");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("first_name");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("last_name");
+
+ b.HasKey("Id");
+
+ b.ToTable("employee");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.cs
new file mode 100644
index 0000000..4e280bd
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/20251211113454_InitialCreate.cs
@@ -0,0 +1,37 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Faura.WebAPI.Infrastructure.Persistence.Migrations
+{
+ ///
+ public partial class InitialCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "employee",
+ columns: table => new
+ {
+ id = table.Column(type: "bigint", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ first_name = table.Column(type: "text", nullable: false),
+ last_name = table.Column(type: "text", nullable: false),
+ email = table.Column(type: "text", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_employee", x => x.id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "employee");
+ }
+ }
+}
diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/EmployeeDbContextModelSnapshot.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/EmployeeDbContextModelSnapshot.cs
new file mode 100644
index 0000000..36972f5
--- /dev/null
+++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/Migrations/EmployeeDbContextModelSnapshot.cs
@@ -0,0 +1,55 @@
+//
+using Faura.WebAPI.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Faura.WebAPI.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(EmployeeDbContext))]
+ partial class EmployeeDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.14")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Faura.WebAPI.Domain.Entities.Employee", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("email");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("first_name");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("last_name");
+
+ b.HasKey("Id");
+
+ b.ToTable("employee");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Templates/Faura.WebAPI/Program.cs b/src/Templates/Faura.WebAPI/Program.cs
index cb68196..93e756f 100644
--- a/src/Templates/Faura.WebAPI/Program.cs
+++ b/src/Templates/Faura.WebAPI/Program.cs
@@ -5,16 +5,19 @@
builder.RegisterDependencies();
builder.RegisterApplicationDependencies();
+builder.Services.RegisterInfrastructureDependencies(builder.Configuration);
+builder.Services.RegisterOptions(builder.Configuration);
var app = builder.Build();
app.ConfigureCommonFauraWebApplication();
+await app.ConfigureInfrastructureAsync(app.Environment);
-app.Run();
+await app.RunAsync();
+// This is needed for the integration tests
+#pragma warning disable S1118 // Utility classes should not have public constructors,
public partial class Program
+#pragma warning restore S1118 // Utility classes should not have public constructors
{
- protected Program()
- {
- }
}
diff --git a/src/Templates/Faura.WebAPI/Properties/launchSettings.json b/src/Templates/Faura.WebAPI/Properties/launchSettings.json
index b41f448..4f0c04d 100644
--- a/src/Templates/Faura.WebAPI/Properties/launchSettings.json
+++ b/src/Templates/Faura.WebAPI/Properties/launchSettings.json
@@ -16,7 +16,7 @@
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5069",
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Local",
+ "ASPNETCORE_ENVIRONMENT": "Development",
"FAURA_ENVIRONMENT": "Development"
}
},
@@ -27,7 +27,7 @@
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7140;http://localhost:5069",
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Local",
+ "ASPNETCORE_ENVIRONMENT": "Development",
"FAURA_ENVIRONMENT": "Development"
}
},
diff --git a/src/Templates/Faura.WebAPI/appsettings.Development.json b/src/Templates/Faura.WebAPI/appsettings.Development.json
index 043d80b..6c76527 100644
--- a/src/Templates/Faura.WebAPI/appsettings.Development.json
+++ b/src/Templates/Faura.WebAPI/appsettings.Development.json
@@ -1,47 +1,47 @@
{
- "Logging": {
- "MinimumLevel": {
- "Default": "Information",
- "Override": {
- "Microsoft": "Error",
- "System": "Error"
- }
- },
- "ApplicationName": "FauraApp",
- "Outputs": {
- "Console": {
- "Enable": true,
- "LogTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} | CorrelationId: {CorrelationId} | ApplicationName: {ApplicationName}{NewLine}{Exception}"
- }
- }
+ "Logging": {
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Error",
+ "System": "Error"
+ }
},
+ "ApplicationName": "FauraApp",
+ "Outputs": {
+ "Console": {
+ "Enable": true,
+ "LogTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} | CorrelationId: {CorrelationId} | ApplicationName: {ApplicationName}{NewLine}{Exception}"
+ }
+ }
+ },
- "Swagger": {
- "Authentication": {
- "OAuth2": {
- "Enable": true,
- "Name": "OAuth2",
- "AuthenticationURL": "{AuthenticationURL-PlaceHolder}",
- "Scopes": {
- "openid": "openid",
- "profile": "profile"
- }
- },
- "Bearer": {
- "Enable": true,
- "Name": "Bearer"
- },
- "BasicAuth": {
- "Enable": false,
- "Name": "Basic"
- },
- "ApiKey": {
- "Enable": false,
- "Name": "X-API-Key",
- "In": "Header" // "Header" o "Query"
- }
+ "Swagger": {
+ "Authentication": {
+ "OAuth2": {
+ "Enable": false,
+ "Name": "OAuth2",
+ "AuthenticationURL": "{AuthenticationURL-PlaceHolder}",
+ "Scopes": {
+ "openid": "openid",
+ "profile": "profile"
}
- },
+ },
+ "Bearer": {
+ "Enable": false,
+ "Name": "Bearer"
+ },
+ "BasicAuth": {
+ "Enable": false,
+ "Name": "Basic"
+ },
+ "ApiKey": {
+ "Enable": false,
+ "Name": "X-API-Key",
+ "In": "Header" // "Header" o "Query"
+ }
+ }
+ },
"JWT": {
@@ -50,7 +50,7 @@
"Audience": "account"
},
- "ConnectionStrings": {
- "Employee": "{connectionString_placeholder}"
- }
+ "ConnectionStrings": {
+ "Employee": "{connectionString_placeholder}"
+ }
}
diff --git a/src/Templates/Faura.WebAPI/appsettings.json b/src/Templates/Faura.WebAPI/appsettings.json
index 183b5fa..6c76527 100644
--- a/src/Templates/Faura.WebAPI/appsettings.json
+++ b/src/Templates/Faura.WebAPI/appsettings.json
@@ -19,7 +19,7 @@
"Swagger": {
"Authentication": {
"OAuth2": {
- "Enable": true,
+ "Enable": false,
"Name": "OAuth2",
"AuthenticationURL": "{AuthenticationURL-PlaceHolder}",
"Scopes": {
@@ -28,7 +28,7 @@
}
},
"Bearer": {
- "Enable": true,
+ "Enable": false,
"Name": "Bearer"
},
"BasicAuth": {