From 574e5ed209d356ea69554c4920001e357a8bf9d6 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 9 Jul 2026 15:45:18 +0200 Subject: [PATCH] Add in-memory DB support for .NET 4.8 and .NET 8 testing Introduced a `DbConnection` constructor in `JobRunnerDbContext` for Entity Framework 6 to enable in-memory testing with the Effort library. Added conditional compilation to support both .NET Framework 4.8 and .NET 8. Implemented `AddInfrastructureInMemory` in `DependencyExtension` to register services with in-memory databases: - For .NET 4.8, uses Effort's transient connection. - For .NET 8, uses EF Core's in-memory provider. Registered AutoMapper in both methods for object mapping. Added `EntityMappingProfile` to define AutoMapper configurations, enforcing explicit DTO-to-entity mappings. These changes improve testability and maintainability across .NET versions. --- .../Data/JobRunnerDbContext.cs | 8 +++ .../DependencyExtension.cs | 54 +++++++++++++++++++ .../Mapping/EntityMappingProfile.cs | 22 ++++++++ 3 files changed, 84 insertions(+) create mode 100644 ECMJobRunner.Infrastructure/Mapping/EntityMappingProfile.cs diff --git a/ECMJobRunner.Infrastructure/Data/JobRunnerDbContext.cs b/ECMJobRunner.Infrastructure/Data/JobRunnerDbContext.cs index 06cbc40..21de427 100644 --- a/ECMJobRunner.Infrastructure/Data/JobRunnerDbContext.cs +++ b/ECMJobRunner.Infrastructure/Data/JobRunnerDbContext.cs @@ -1,5 +1,6 @@ #if NET48 using System.Data.Entity; +using System.Data.Common; #else using Microsoft.EntityFrameworkCore; #endif @@ -41,6 +42,13 @@ namespace ECMJobRunner.Infrastructure.Data public JobRunnerDbContext(string connectionString) : base(connectionString) { } + + /// + /// Constructor with DbConnection for Entity Framework 6 (used for InMemory testing with Effort) + /// + public JobRunnerDbContext(DbConnection connection) : base(connection, contextOwnsConnection: true) + { + } #else /// /// Constructor for Entity Framework Core (.NET 8) diff --git a/ECMJobRunner.Infrastructure/DependencyExtension.cs b/ECMJobRunner.Infrastructure/DependencyExtension.cs index 2a432f3..7eed1f6 100644 --- a/ECMJobRunner.Infrastructure/DependencyExtension.cs +++ b/ECMJobRunner.Infrastructure/DependencyExtension.cs @@ -45,5 +45,59 @@ namespace ECMJobRunner.Infrastructure return services; } + +#if NET48 + /// + /// Add Infrastructure services with InMemory database for testing (.NET Framework 4.8 - uses Effort) + /// + /// Service collection + /// Service collection for chaining + public static IServiceCollection AddInfrastructureInMemory(this IServiceCollection services) + { + // Register DbContext as scoped with Effort InMemory connection + services.AddScoped(provider => + { + var connection = Effort.DbConnectionFactory.CreateTransient(); + return new JobRunnerDbContext(connection); + }); + + // Register AutoMapper + services.AddAutoMapper(typeof(DependencyExtension).Assembly); + + // Register repositories as scoped (same lifetime as DbContext) + services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } +#else + /// + /// Add Infrastructure services with InMemory database for testing (.NET 8 - uses EF Core InMemory) + /// + /// Service collection + /// Optional database name (default: random GUID) + /// Service collection for chaining + public static IServiceCollection AddInfrastructureInMemory(this IServiceCollection services, string? databaseName = null) + { + var dbName = databaseName ?? $"TestDb_{System.Guid.NewGuid()}"; + + // Register DbContext as scoped with InMemory database + services.AddDbContext(options => + options.UseInMemoryDatabase(dbName)); + + // Register AutoMapper + services.AddAutoMapper(typeof(DependencyExtension).Assembly); + + // Register repositories as scoped (same lifetime as DbContext) + services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } +#endif } } diff --git a/ECMJobRunner.Infrastructure/Mapping/EntityMappingProfile.cs b/ECMJobRunner.Infrastructure/Mapping/EntityMappingProfile.cs new file mode 100644 index 0000000..acb1e05 --- /dev/null +++ b/ECMJobRunner.Infrastructure/Mapping/EntityMappingProfile.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using ECMJobRunner.Domain.Entities; + +namespace ECMJobRunner.Infrastructure.Mapping +{ + /// + /// AutoMapper profile for entity mappings + /// + public class EntityMappingProfile : Profile + { + /// + /// Constructor configuring AutoMapper mappings for all entities + /// + public EntityMappingProfile() + { + // Note: object -> Entity mappings are intentionally removed + // AutoMapper cannot map from object type due to reflection limitations + // Callers should use explicit DTO types and create specific mappings + // Example: CreateMap() in your own AutoMapper profile + } + } +}