diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 5b66d8fb..4f2cabdf 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -21,6 +21,7 @@
+
diff --git a/src/Verify.EntityFramework.Tests/DbUpdateExceptionTests.cs b/src/Verify.EntityFramework.Tests/DbUpdateExceptionTests.cs
index 33d56df1..6aa628c9 100644
--- a/src/Verify.EntityFramework.Tests/DbUpdateExceptionTests.cs
+++ b/src/Verify.EntityFramework.Tests/DbUpdateExceptionTests.cs
@@ -4,7 +4,7 @@ public class DbUpdateExceptionTests
[Test]
public async Task Run()
{
- var instance = new SqlInstance(builder => new(builder.Options));
+ var instance = new SqlInstanceProvider(builder => new(builder.Options));
var id = Guid.NewGuid();
var entity = new TestEntity
{
diff --git a/src/Verify.EntityFramework.Tests/GlobalUsings.cs b/src/Verify.EntityFramework.Tests/GlobalUsings.cs
index 55bfb73a..e7aba465 100644
--- a/src/Verify.EntityFramework.Tests/GlobalUsings.cs
+++ b/src/Verify.EntityFramework.Tests/GlobalUsings.cs
@@ -1,11 +1,14 @@
-global using System.ComponentModel.DataAnnotations.Schema;
+global using System.ComponentModel.DataAnnotations.Schema;
global using System.Net.Http.Json;
global using Argon;
+global using DotNet.Testcontainers.Containers;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.Mvc.Testing;
global using Microsoft.AspNetCore.TestHost;
+global using Microsoft.Data.SqlClient;
global using Microsoft.Data.Sqlite;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.DependencyInjection;
-global using Microsoft.Extensions.Hosting;
\ No newline at end of file
+global using Microsoft.Extensions.Hosting;
+global using Testcontainers.MsSql;
\ No newline at end of file
diff --git a/src/Verify.EntityFramework.Tests/Snippets/ContainerSqlDatabase.cs b/src/Verify.EntityFramework.Tests/Snippets/ContainerSqlDatabase.cs
new file mode 100644
index 00000000..8063050e
--- /dev/null
+++ b/src/Verify.EntityFramework.Tests/Snippets/ContainerSqlDatabase.cs
@@ -0,0 +1,13 @@
+public sealed class ContainerSqlDatabase(Func dbContext) : ISqlDatabase
+ where TDbContext : DbContext
+{
+ public string ConnectionString => Context.Database.GetConnectionString()!;
+
+ public TDbContext Context { get; } = dbContext();
+
+ public TDbContext NewDbContext() => dbContext();
+
+ public Task AddData(params object[] entities) => Context.AddData(entities);
+
+ public ValueTask DisposeAsync() => ValueTask.CompletedTask;
+}
\ No newline at end of file
diff --git a/src/Verify.EntityFramework.Tests/Snippets/DbContextBuilder.cs b/src/Verify.EntityFramework.Tests/Snippets/DbContextBuilder.cs
index bdf6529a..9e3e83e7 100644
--- a/src/Verify.EntityFramework.Tests/Snippets/DbContextBuilder.cs
+++ b/src/Verify.EntityFramework.Tests/Snippets/DbContextBuilder.cs
@@ -1,4 +1,4 @@
-// LocalDb is used to make the sample simpler.
+// LocalDb is used to make the sample simpler.
// Replace with a real DbContext
public static class DbContextBuilder
@@ -14,7 +14,7 @@ static DbContextBuilder()
});
descriptiveAliasSqlInstance = new(
buildTemplate: CreateDb,
- storage: Storage.FromSuffix("DescriptiveTableAliases"),
+ storageSuffix: "DescriptiveTableAliases",
constructInstance: builder =>
{
builder.EnableRecording();
@@ -23,7 +23,7 @@ static DbContextBuilder()
});
descriptiveParameterNamesSqlInstance = new(
buildTemplate: CreateDb,
- storage: Storage.FromSuffix("DescriptiveParameterNames"),
+ storageSuffix: "DescriptiveParameterNames",
constructInstance: builder =>
{
builder.EnableRecording();
@@ -32,9 +32,9 @@ static DbContextBuilder()
});
}
- static SqlInstance sqlInstance;
- static SqlInstance descriptiveAliasSqlInstance;
- static SqlInstance descriptiveParameterNamesSqlInstance;
+ static SqlInstanceProvider sqlInstance;
+ static SqlInstanceProvider descriptiveAliasSqlInstance;
+ static SqlInstanceProvider descriptiveParameterNamesSqlInstance;
static async Task CreateDb(SampleDbContext data)
{
@@ -85,12 +85,12 @@ static async Task CreateDb(SampleDbContext data)
await data.SaveChangesAsync();
}
- public static Task> GetDatabase([CallerMemberName] string suffix = "")
+ public static Task> GetDatabase([CallerMemberName] string suffix = "")
=> sqlInstance.Build(suffix);
- public static Task> GetDescriptiveAliasDatabase([CallerMemberName] string suffix = "")
+ public static Task> GetDescriptiveAliasDatabase([CallerMemberName] string suffix = "")
=> descriptiveAliasSqlInstance.Build(suffix);
- public static Task> GetDescriptiveParameterNamesDatabase([CallerMemberName] string suffix = "")
+ public static Task> GetDescriptiveParameterNamesDatabase([CallerMemberName] string suffix = "")
=> descriptiveParameterNamesSqlInstance.Build(suffix);
}
\ No newline at end of file
diff --git a/src/Verify.EntityFramework.Tests/Snippets/ISqlDatabase.cs b/src/Verify.EntityFramework.Tests/Snippets/ISqlDatabase.cs
new file mode 100644
index 00000000..6791432c
--- /dev/null
+++ b/src/Verify.EntityFramework.Tests/Snippets/ISqlDatabase.cs
@@ -0,0 +1,11 @@
+public interface ISqlDatabase : IAsyncDisposable
+ where TDbContext : DbContext
+{
+ string ConnectionString { get; }
+
+ TDbContext Context { get; }
+
+ TDbContext NewDbContext();
+
+ Task AddData(params object[] entities);
+}
\ No newline at end of file
diff --git a/src/Verify.EntityFramework.Tests/Snippets/LocalDbSqlDatabase.cs b/src/Verify.EntityFramework.Tests/Snippets/LocalDbSqlDatabase.cs
new file mode 100644
index 00000000..4c436125
--- /dev/null
+++ b/src/Verify.EntityFramework.Tests/Snippets/LocalDbSqlDatabase.cs
@@ -0,0 +1,13 @@
+public sealed class LocalDbSqlDatabase(SqlDatabase sqlDatabase) : ISqlDatabase
+ where TDbContext : DbContext
+{
+ public string ConnectionString { get; } = sqlDatabase.ConnectionString;
+
+ public TDbContext Context { get; } = sqlDatabase.Context;
+
+ public TDbContext NewDbContext() => sqlDatabase.NewDbContext();
+
+ public Task AddData(params object[] entities) => sqlDatabase.AddData(entities);
+
+ public ValueTask DisposeAsync() => sqlDatabase.DisposeAsync();
+}
\ No newline at end of file
diff --git a/src/Verify.EntityFramework.Tests/Snippets/SqlInstanceProvider.cs b/src/Verify.EntityFramework.Tests/Snippets/SqlInstanceProvider.cs
new file mode 100644
index 00000000..528809ca
--- /dev/null
+++ b/src/Verify.EntityFramework.Tests/Snippets/SqlInstanceProvider.cs
@@ -0,0 +1,107 @@
+public class SqlInstanceProvider : IAsyncDisposable
+ where TDbContext : DbContext
+{
+ readonly TemplateFromContext? buildTemplate;
+ readonly ConstructInstance constructInstance;
+
+ SemaphoreSlim semaphore = new(1);
+ SqlInstance? sqlInstance;
+ MsSqlContainer? sqlContainer;
+
+ public SqlInstanceProvider(ConstructInstance constructInstance, TemplateFromContext? buildTemplate = null, string? storageSuffix = null)
+ {
+ this.buildTemplate = buildTemplate;
+ this.constructInstance = constructInstance;
+ if (string.Equals(Environment.GetEnvironmentVariable("VERIFY_ENTITYFRAMEWORK_TESTS_SQLENGINE"), "Docker", StringComparison.OrdinalIgnoreCase) || !OperatingSystem.IsWindows())
+ {
+ var suffix = storageSuffix == null ? "" : $".{storageSuffix}";
+ sqlContainer = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2025-latest")
+ .WithName($"Verify.EntityFramework.Tests{suffix}")
+ .WithReuse(true)
+ .Build();
+ }
+ else
+ {
+ sqlInstance = new(
+ buildTemplate: buildTemplate,
+ storage: storageSuffix == null ? null : Storage.FromSuffix(storageSuffix),
+ constructInstance: constructInstance);
+ }
+ }
+
+ public async Task> Build(IEnumerable