### SQL Script File Format Example Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Run-SQL-Server-script Example of a SQL script file format. Each SQL command must be followed by 'GO' on a new line to be correctly interpreted by the execution method. ```sql INSERT INTO Authors (Name) VALUES('Row 1') GO INSERT INTO Authors (Name) VALUES('Row 2') GO ``` -------------------------------- ### Create Options with EF Core Logging Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQL-Server-databases Use `CreateUniqueClassOptionsWithLogTo` to capture EF Core logs. This example shows capturing logs into a list for analysis. ```csharp var logs = new List(); var options = this.CreateUniqueClassOptionsWithLogTo(log => logs.Add(log)); using var context = new BookContext(options); //... rest of test left out ``` -------------------------------- ### Seed Database with Extension Method Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Rules-for-tests-using-EF-Core Demonstrates creating a reusable extension method for seeding test data. This approach makes tests cleaner, easier to understand, and simplifies data setup maintenance. ```csharp SeedDatabaseFourBooks() ``` -------------------------------- ### Get Empty Database with Correct Schema Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQLite-in-memory-databases Call `EnsureCreated()` on the `DbContext.Database` object after creating the in-memory database options to initialize the database schema. ```csharp using var options = SqliteInMemory.CreateOptions(); using var context = new BookContext(options); context.Database.EnsureCreated(); ``` -------------------------------- ### Test Cosmos DB Setup with Default Database Name Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Create-Cosmos-DB-options Use this method to automatically set the database name based on the type of the context. Ensure the database is deleted and created before proceeding with tests. ```csharp public async Task TestAddCosmosBookWithReviewsOk() { //SETUP var options = this.GetCosmosDbToEmulatorOptions(); using var context = new CosmosDbContext(options); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); //ATTEMPT var cBook = new CosmosBook { CosmosBookId = 1, Title = "Book Title", PublishedDate = new DateTime(2019, 1,1), }; context.Add(cBook); await context.SaveChangesAsync(); //VERIFY await context.Books.FindAsync(1).ShouldNotBeNull(); } ``` -------------------------------- ### Filter EF Core logs with LogToOptions Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Tools-for-capturing-EF-Core-logging This example demonstrates using LogToOptions to control log output. It filters logs to only show database commands and toggles output visibility using ShowLog. ```csharp [Fact] public void TestEfCoreLoggingCheckSqlOutputShowLog() { //SETUP var logs = new List(); var logToOptions = new LogToOptions { ShowLog = false, OnlyShowTheseCategories = new[] { DbLoggerCategory.Database.Command.Name } }; var options = SqliteInMemory.CreateOptionsWithLogTo (log => logs.Add(log), logToOptions); using var context = new BookContext(options); context.Database.EnsureCreated(); //no logs from these context.SeedDatabaseFourBooks(); //no logs from these //ATTEMPT logToOptions.ShowLog = true; //Turn on log output var book = context.Books .Single(x => x.Reviews.Count() > 1); //Get log from this //VERIFY logs.Count.ShouldEqual(1); logs.Single().Should... ``` -------------------------------- ### Test Cosmos DB Setup with Explicit Database Name Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Create-Cosmos-DB-options Use this overload to specify a custom database name by providing it as a string argument. The `makeMethodUnique` parameter can also be used here to ensure method-specific naming. ```csharp public async Task TestWithGivenNameOk() { //SETUP var options = "MyDatabasName".GetCosmosDbToEmulatorOptions(true); using var context = new CosmosDbContext(options); //... etc. } ``` -------------------------------- ### Test Cosmos DB Setup with Method-Unique Database Name Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Create-Cosmos-DB-options Set the `makeMethodUnique` parameter to true to ensure the database name is unique to the calling method, preventing potential naming conflicts during testing. ```csharp public async Task TestWithDatabaseNameUniqueOk() { //SETUP var options = this.GetCosmosDbToEmulatorOptions(true); using var context = new CosmosDbContext(options); //... etc. } ``` -------------------------------- ### Get an Empty Database with Correct Schema Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-Cosmos-DB-databases Provides a method to ensure an empty Cosmos DB database with the correct schema by calling EnsureDeletedAsync followed by EnsureCreatedAsync. ```csharp var options = this.CreateUniqueClassCosmosDbEmulator(); using var context = new CosmosDbContext(options); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); ``` -------------------------------- ### Add Extra Options to PostgreSQL DbContextOptionsBuilder Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-PostgreSQL-databases Allows setting extra options at the DbContextOptionsBuilder level when creating PostgreSQL test database options. Example shows disabling query tracking. ```csharp //... previous code removed to focus on the feature var options2 = this.CreatePostgreSqlUniqueClassOptions( builder => builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); using (var context = new BookContext(options2)) { //VERIFY var book = context.Books.First(); context.Entry(book).State.ShouldEqual(EntityState.Detached); } ``` -------------------------------- ### Configure Advanced In-Memory SQLite Options Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Sqlite-in-memory-test-database This overload allows for custom configuration of the DbContextOptionsBuilder, enabling overrides for connection strings or query tracking behavior. Useful for more complex testing setups. ```csharp //... previous code removed to focus on this feature var options2 = SqliteInMemory.CreateOptions(builder => { builder.UseSqlite(connection); //overrides current connection with existing connection builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); //change track option }); using (var context = new BookContext(options2)) { //VERIFY var book = context.Books.First(); context.Entry(book).State.ShouldEqual(EntityState.Detached); } ``` -------------------------------- ### Test Sqlite Two Instances BAD Example Source: https://github.com/jonpsmith/efcore.testsupport/blob/main/Version5UpgradeDocs.md Demonstrates a failing unit test scenario with multiple SqliteInMemory DbContext instances due to automatic connection disposal. This highlights the breaking change in version 5. ```csharp public void TestSqliteTwoInstancesBAD() { //SETUP var options = SqliteInMemory.CreateOptions(); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); } using (var context = new BookContext(options)) { //ATTEMPT //THIS WILL FAIL!!!! THIS WILL FAIL!!!! THIS WILL FAIL!!!! var books = context.Books.ToList(); //VERIFY books.Last().Reviews.ShouldBeNull(); } } ``` -------------------------------- ### Test Adding a Cosmos Book with Reviews Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-Cosmos-DB-databases Demonstrates setting up the Cosmos DB emulator, creating a database, adding a book, and verifying its existence using EF Core async methods. ```csharp public async Task TestAddCosmosBookWithReviewsOk() { //SETUP var options = this.CreateUniqueClassCosmosDbEmulator(); using var context = new CosmosDbContext(options); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); //ATTEMPT var cBook = new CosmosBook { CosmosBookId = 1, Title = "Book Title", PublishedDate = new DateTime(2019, 1,1), }; context.Add(cBook); await context.SaveChangesAsync(); //VERIFY await context.Books.FindAsync(1).ShouldNotBeNull(); } ``` -------------------------------- ### Create Empty Database via Wipe Method Source: https://github.com/jonpsmith/efcore.testsupport/wiki/5.-Quickly-create-empty-database The `CreateEmptyViaWipe` extension method quickly wipes all rows from tables, making it about 100 times faster than EnsureDeleted/EnsureCreated. It requires a DbContext and has parameters for custom wiping logic. ```csharp [Fact] public void TestExampleSqlDatabaseOk() { //SETUP var options = this.CreateUniqueClassOptions(); using (var context = new EfCoreContext(options)) { context.CreateEmptyViaWipe(); //ATTEMPT context.SeedDatabaseFourBooks(); //VERIFY context.Books.Count().ShouldEqual(4); } } ``` -------------------------------- ### Delete All SQL Server Test Databases Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Deletes all SQL Server databases whose names start with a specified base name. Typically used in a one-time teardown command. ```csharp // Place in a dedicated "UnitCommands" class to run manually. public class DeleteAllUnitTestDatabases { [RunnableInDebugOnly] public void DeleteSqlServerDatabases() { var numDeleted = DatabaseTidyHelper.DeleteAllSqlServerTestDatabases(); // Output: "Deleted 12 SQL Server test databases." Console.WriteLine($"Deleted {numDeleted} SQL Server test databases."); } [RunnableInDebugOnly] public void DeletePostgreSqlDatabases() { var numDeleted = DatabaseTidyHelper.DeleteAllPostgreSqlTestDatabases(); Console.WriteLine($"Deleted {numDeleted} PostgreSQL test databases."); } } ``` -------------------------------- ### Create Per-Method Cosmos DB Emulator Options with Logging Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Creates a per-method Cosmos DB database on the emulator and directs EF Core logging to a provided action. Useful for debugging container operations. Ensure the CosmosOrderContext is configured for Cosmos DB. ```csharp public class TestCosmosQueries { [Fact] public async Task CosmosDb_LogsContainerOperations() { var logs = new List(); var options = this.CreateUniqueMethodCosmosDbEmulatorWithLogTo( log => logs.Add(log), new LogToOptions { LogLevel = LogLevel.Debug }); using var context = new CosmosOrderContext(options); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); context.Orders.Add(new Order { Id = Guid.NewGuid(), Total = 12.50m }); await context.SaveChangesAsync(); logs.Any(l => l.Contains("SaveChanges")).ShouldBeTrue(); } } ``` -------------------------------- ### Configure Base Connection Strings in appsettings.json Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Creating-connection-strings Define base connection strings for SQL Server and PostgreSQL in your `appsettings.json` file. Ensure the database name ends with 'Test' for safety. ```json { "ConnectionStrings": { "UnitTestConnection": "Server=(localdb)\mssqllocaldb;Database=EfCore.TestSupport-Test;Trusted_Connection=True;MultipleActiveResultSets=true", "PostgreSqlConnection": "host=127.0.0.1;Database=TestSupport-Test;Username=postgres;Password=your-password" } } ``` -------------------------------- ### Using EnsureClean for SQL Server Database Source: https://github.com/jonpsmith/efcore.testsupport/wiki/EnsureClean-your-database Demonstrates how to use the EnsureClean extension method with a SQL Server database context in a test. ```csharp [Fact] public void TestSqlServerEnsureClean() { //SETUP //ATTEMPT var options = this.CreateUniqueClassOptions(); using var context = new EfCoreContext(options) context.Database.EnsureClean(); //... left of test left out } ``` -------------------------------- ### Clear Change Tracker in EF Core Tests Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Rules-for-tests-using-EF-Core Use context.ChangeTracker.Clear() at the end of SETUP and ATTEMPT stages to prevent EF Core's change tracking from hiding database access errors. ```csharp [Fact] public void TestBookDbContextAddFourBooksLoadRelationshipsOk() { //SETUP var options = SqliteInMemory.CreateOptions(); using var context = new BookDbContext(options); context.Database.EnsureCreated(); context.SeedDatabaseFourBooks(); context.ChangeTracker.Clear(); //ATTEMPT var book = context.Books.First(); book.Price = 123; context.SaveChanges(); //VERIFY context.ChangeTracker.Clear(); var verifyBook = context.Books.First(); verifyBook.Price.ShouldEqual(123); } ``` -------------------------------- ### Create Per-Method PostgreSQL Options Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Appends class and method names to create a unique PostgreSQL database for each test method. Ensure the AppDbContext is configured to use PostgreSQL. ```csharp public class TestInventoryService { [Fact] public void ReserveStock_DeductsFromInventory() { // DB: "MyAppTest_TestInventoryService_ReserveStock_DeductsFromInventory" var options = this.CreatePostgreSqlUniqueMethodOptions(); using var context = new AppDbContext(options); context.Database.EnsureClean(); context.Products.Add(new Product { Name = "Gadget", Stock = 50 }); context.SaveChanges(); var product = context.Products.Single(); product.Stock -= 10; context.SaveChanges(); context.Products.Single().Stock.ShouldEqual(40); } } ``` -------------------------------- ### Create Per-Class Cosmos DB Emulator Options Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Connects to the Azure Cosmos DB Emulator using default credentials. The database name is derived from the test class name. Ensure the CosmosOrderContext is configured for Cosmos DB. ```csharp public class TestCosmosOrderRepository { [Fact] public async Task CosmosDb_UniqueClassOptions_StoreAndRetrieve() { var options = this.CreateUniqueClassCosmosDbEmulator(); using var context = new CosmosOrderContext(options); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); context.Orders.Add(new Order { Id = Guid.NewGuid(), Total = 99.99m }); await context.SaveChangesAsync(); var order = await context.Orders.FirstAsync(); order.Total.ShouldEqual(99.99m); } } ``` -------------------------------- ### Obtain EF Core Logging Data Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-Cosmos-DB-databases Demonstrates how to capture EF Core logs by using the CreateUniqueMethodCosmosDbEmulatorWithLogTo method, which allows logging to a provided list. ```csharp var logs = new List(); var options = this.CreateUniqueMethodCosmosDbEmulatorWithLogTo(log => logs.Add(log)); using var context = new BookContext(options); //... rest of test left out ``` -------------------------------- ### Load Default appsettings.json Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Accessing-the-appsettings.json-file Loads configuration from the default 'appsettings.json' file in the unit test project. This method does not fail if the file is missing. ```csharp var config = AppSettings.GetConfiguration(); var connectionString = config .GetConnectionString("DefaultConnection"); ``` -------------------------------- ### Ensure Empty Database with EnsureDeleted and EnsureCreated Source: https://github.com/jonpsmith/efcore.testsupport/wiki/5.-Quickly-create-empty-database Use EnsureDeleted and EnsureCreated to create an empty database with the latest schema. This method is foolproof but can be slow, taking around 10 seconds. ```csharp context.Database.EnsureDeleted(); context.Database.EnsureCreated(); ``` -------------------------------- ### TimeThings Constructor Overloads Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Simple-performance-stopwatch Demonstrates the different overloads for the TimeThings constructor, showing how to provide custom messages and specify the number of runs for averaged timing. ```csharp public TimeThings(ITestOutputHelper output, string message = "", int numRuns = 0) ``` ```text new TimeThings(_output) ``` ```text new TimeThings(_output, "Sample 1") ``` ```text new TimeThings(_output, "read book", 500) ``` -------------------------------- ### Get Absolute Path to TestData Directory Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Returns the absolute file system path to the 'TestData/' directory (or an alternate configured directory) within the calling test project. Useful for directory operations or listing files. ```csharp using System.IO; using Xunit; // Assuming TestData is a static class with a GetTestDataDir method. public class TestDataDirectoryTests { [Fact] public void TestData_GetTestDataDir_ReturnsAbsolutePath() { var testDataDir = TestData.GetTestDataDir(); Directory.Exists(testDataDir).ShouldBeTrue(); // Use it to enumerate all SQL scripts available: var scripts = Directory.GetFiles(testDataDir, "*.sql"); scripts.Length.ShouldBeInRange(1, 100); Console.WriteLine($"TestData dir: {testDataDir}"); Console.WriteLine($"Found {scripts.Length} SQL scripts."); } } ``` -------------------------------- ### TimeThings Stopwatch Utility Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Use TimeThings to measure the execution time of code blocks. It starts a Stopwatch on construction and stops it on Dispose. It can report results via a callback or directly to an ITestOutputHelper, and supports calculating per-iteration averages. ```csharp public class TestPerformance { private readonly ITestOutputHelper _output; public TestPerformance(ITestOutputHelper output) => _output = output; [Fact] public void TimeThings_MeasuresBulkInsert() { const int numBooks = 1000; using var options = SqliteInMemory.CreateOptions(); using var context = new BookContext(options); context.Database.EnsureCreated(); TimeThingResult result = null; using (new TimeThings(r => result = r, "Bulk insert 1000 books", numBooks)) { context.Books.AddRange( Enumerable.Range(1, numBooks) .Select(i => new Book { Title = $"Book {i}", Price = i * 0.99m }))); context.SaveChanges(); } // Output: "1,000 x Bulk insert 1000 books took 234.50 ms., ave. per run = 0.23 ms." _output.WriteLine(result.ToString()); result.TotalTimeMilliseconds.ShouldBeInRange(0.0, 60_000.0); result.NumRuns.ShouldEqual(numBooks); // Alternative: write directly to ITestOutputHelper. using (new TimeThings(_output, "Query all books")) { _ = context.Books.ToList(); } } } ``` -------------------------------- ### Output EF Core Logs to Unit Test Output Window Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Capture-EF-Core-logging Use `CreateUniqueClassOptionsWithLogging` with `ITestOutputHelper.WriteLine` to send EF Core logs to the unit test output window. This is helpful for debugging database creation. ```csharp [RunnableInDebugOnly] public void CaptureSqlEfCoreCreatesDatabaseToConsole() { //SETUP var options = this.CreateUniqueClassOptionsWithLogging( log => _output.WriteLine(log.Message)); using (var context = new BookContext(options)) { //ATTEMPT context.Database.EnsureDeleted(); context.Database.EnsureCreated(); } } ``` -------------------------------- ### Obtain EF Core Logging Data for PostgreSQL Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-PostgreSQL-databases Creates PostgreSQL test database options and captures EF Core logs into a list. Useful for debugging. ```csharp var logs = new List(); var options = this.CreatePostgreSqlUniqueClassOptionsWithLogTo(log => logs.Add(log)); using var context = new BookContext(options); //... rest of test left out ``` -------------------------------- ### Ensure Deleted and Ensured Created for Database Reset Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Rules-for-tests-using-EF-Core This approach involves calling EF Core's EnsureDeleted method followed by EnsuredCreated. It's a standard way to reset the database to an empty state and apply the current EF Core model schema at the start of each test. ```csharp EnsuredDeleted() EnsuredCreated() ``` -------------------------------- ### Load appsettings.json from a Relative Path Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Accessing-the-appsettings.json-file Loads configuration from a specified JSON file located in a different directory relative to the calling assembly. Useful for accessing configuration from other projects. ```csharp var mainConfig = AppSettings.GetConfiguration("../MyAspNetCoreApp/"); var connectionString = mainConfig.GetConnectionString("DefaultConnection"); ``` -------------------------------- ### Create ILogger with MyLoggerProviderActionOut Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Handling-ILogger-in-your-tests Use this to create a generic ILogger instance for testing. It captures log output via an action and allows configuration of the minimum log level. ```csharp public List Logs { get; } = new List(); ILogger logger = new LoggerFactory( new[] { new MyLoggerProviderActionOut(log => Logs.Add(log)) }) .CreateLogger(); ``` -------------------------------- ### Create Empty PostgreSQL Database with Schema Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-PostgreSQL-databases Ensures the PostgreSQL database is created with the correct schema. This is a faster alternative to EnsureDeleted/EnsureCreated. ```csharp var options = this.CreatePostgreSqlUniqueClassOptions(); using var context = new BookContext(options); context.Database.EnsureCreated(); ``` -------------------------------- ### Create SQL Server DB Options with Logging Per Test Class Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Provides per-class database naming for SQL Server and integrates EF Core's LogTo for diagnosing queries. Captures logs in a list for inspection. ```csharp public class TestOrderService { private readonly ITestOutputHelper _output; public TestOrderService(ITestOutputHelper output) => _output = output; [Fact] public void SqlServer_LogsExecutedCommands() { var logs = new List(); var options = this.CreateUniqueClassOptionsWithLogTo( log => logs.Add(log), new LogToOptions { LogLevel = LogLevel.Information }); using var context = new BookContext(options); context.Database.EnsureClean(); var books = context.Books.Where(b => b.Price > 30).ToList(); // Inspect and decode the first SQL command log entry. var commandLog = logs.FirstOrDefault(l => l.Contains("SELECT")); _output.WriteLine(commandLog ?? "No SELECT found"); commandLog.ShouldNotBeNull(); } } ``` -------------------------------- ### Create Cosmos DB Options with Method Name Suffix Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-Cosmos-DB-databases Generates Cosmos DB options using a connection string from appsettings.json, appending the type name and method name to the database name. ```csharp var options = this.CreateUniqueMethodCosmosDbEmulator(); using var context = new EfCoreContext(options)) ``` -------------------------------- ### Create PostgreSQL Unique Class Options Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-PostgreSQL-databases Generates EF Core options for a PostgreSQL database with a class-level unique database name suffix. Useful for xUnit tests running in parallel. ```csharp [Fact] public void TestPostgreSqlUniqueClassOk() { //SETUP //ATTEMPT var options = this.CreatePostgreSqlUniqueClassOptions(); using (var context = new BookContext(options)) { //VERIFY var builder = new NpgsqlConnectionStringBuilder( context.Database.GetDbConnection().ConnectionString); builder.Database.ShouldEndWith(GetType().Name); } } ``` -------------------------------- ### Create PostgreSQL Unique Method Options Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-PostgreSQL-databases Generates EF Core options for a PostgreSQL database with a method-level unique database name suffix. Generally not needed with xUnit as methods run serially. ```csharp [Fact] public void TestPostgreSqUniqueMethodOk() { //SETUP //ATTEMPT var options = this.CreatePostgreSqlUniqueMethodOptions(); using (var context = new BookContext(options)) { //VERIFY var builder = new NpgsqlConnectionStringBuilder( context.Database.GetDbConnection().ConnectionString); builder.Database .ShouldEndWith($"{GetType().Name}_{nameof(TestPostgreSqUniqueMethodOk)}" ); } } ``` -------------------------------- ### Create Unique SQL Server DB Options Per Test Class Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Generates DbContextOptions for SQL Server, creating a unique database for each test class by appending the class name to the base database name. Requires 'UnitTestConnection' in appsettings.json. ```json // appsettings.json (in your test project root): // { // "ConnectionStrings": { // "UnitTestConnection": "Server=(localdb)\mssqllocaldb;Database=MyAppTest;Trusted_Connection=True" // } // } ``` ```csharp public class TestBookRepository { [Fact] public void SqlServer_UniqueClassOptions_CreateAndQuery() { // Creates connection to "MyAppTest_TestBookRepository" var options = this.CreateUniqueClassOptions(); using var context = new BookContext(options); context.Database.EnsureClean(); // EnsureDeleted + EnsureCreated context.Books.Add(new Book { Title = "Clean Architecture", Price = 44.99m }); context.SaveChanges(); context.Books.Count().ShouldEqual(1); } } ``` -------------------------------- ### Load AppSettings.json Configuration Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Loads the appsettings.json file from the test project's root directory. Use this to access configuration settings like connection strings or feature flags within your tests. ```csharp using Microsoft.Extensions.Configuration; using Xunit; // Assuming AppSettings is a static class with a GetConfiguration method // and the test project has an appsettings.json file. public class AppSettingsTests { [Fact] public void AppSettings_ReadsConnectionString() { var config = AppSettings.GetConfiguration(); var connStr = config.GetConnectionString("UnitTestConnection"); connStr.ShouldNotBeNull(); connStr.ShouldContain("Database="); // Read a custom setting. var featureFlag = config["FeatureFlags:EnableExperiment"]; Console.WriteLine($"Connection: {connStr}"); Console.WriteLine($"FeatureFlag: {featureFlag}"); } } ``` -------------------------------- ### Add Extra DbContextOptionsBuilder Options Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQL-Server-databases This demonstrates how to pass additional configuration to the DbContextOptionsBuilder, such as setting query tracking behavior. ```csharp var options = this.CreateUniqueClassOptions( //sets a tracking behavior builder => builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); using (var context = new BookContext(options)) { //VERIFY var book = context.Books.First(); context.Entry(book).State.ShouldEqual(EntityState.Detached); } ``` -------------------------------- ### Create In-Memory Database Options Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Rules-for-tests-using-EF-Core Use this method to create options for an in-memory SQLite database. This is useful for ensuring a unique and isolated database for tests. ```csharp SqliteInMemory.CreateOptions() ``` -------------------------------- ### SqliteInMemory.CreateOptionsWithLogTo Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Creates disposable DbContext options for an SQLite in-memory database, including EF Core logging capabilities. Captures all EF Core log messages to a provided action, with options to filter and format logs. ```APIDOC ## SqliteInMemory.CreateOptionsWithLogTo ### Description Same as `CreateOptions` but attaches an EF Core `LogTo` sink so every EF Core log message is passed to the supplied `Action`. An optional `LogToOptions` parameter controls log level, category filtering, and format. ### Method Signature `SqliteInMemory.CreateOptionsWithLogTo(Action logTo, Action> builder = null, LogToOptions logToOptions = null)` ### Parameters - `T` (generic type): The DbContext type. - `logTo` (Action): An action that receives each log message as a string. - `builder` (Action>, optional): An action to configure the DbContextOptionsBuilder. - `logToOptions` (LogToOptions, optional): Options to control log level, category filtering, and format. ### Returns `DbContextOptionsDisposable`: An object that manages the disposable DbContext options and the underlying SQLite connection. ### Example Usage ```csharp [Fact] public void SqliteInMemory_CaptureGeneratedSql() { var logs = new List(); using var options = SqliteInMemory.CreateOptionsWithLogTo( log => logs.Add(log), new LogToOptions { LogLevel = LogLevel.Information, OnlyShowTheseCategories = new[] { DbLoggerCategory.Database.Command.Name } }); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); context.Books.Add(new Book { Title = "Domain-Driven Design", Price = 49.99m }); context.SaveChanges(); } // All SQL commands executed against the in-memory DB are captured. logs.Any(l => l.Contains("INSERT")).ShouldBeTrue(); // Expected output example: // "Information,CommandExecuted: Executed DbCommand (0ms) [Parameters=...] INSERT INTO ..." } ``` ``` -------------------------------- ### Create Unique PostgreSQL DB Options Per Test Class Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Generates DbContextOptions for PostgreSQL using Npgsql, creating a unique database per test class. Reads 'PostgreSqlConnection' from appsettings.json and enforces a 'Test' suffix and 64-character limit. ```json // appsettings.json: // { // "ConnectionStrings": { // "PostgreSqlConnection": "Host=localhost;Database=MyAppTest;Username=postgres;Password=secret" // } // } ``` ```csharp public class TestProductRepository { [Fact] public void PostgreSql_UniqueClassOptions_BasicTest() { // DB name: "MyAppTest_TestProductRepository" var options = this.CreatePostgreSqlUniqueClassOptions(); using var context = new AppDbContext(options); context.Database.EnsureClean(); context.Products.Add(new Product { Name = "Widget", Stock = 100 }); context.SaveChanges(); context.Products.Single().Name.ShouldEqual("Widget"); } } ``` -------------------------------- ### Create non-generic ILogger with MyLoggerProviderActionOut Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Handling-ILogger-in-your-tests This snippet shows how to create a non-generic ILogger instance for testing purposes. It captures log output and requires a category name. ```csharp public List Logs { get; } = new List(); ILogger logger = new LoggerFactory( new[] { new MyLoggerProviderActionOut(Logs.Add) }) .CreateLogger("category name"); ``` -------------------------------- ### Generate Unique PostgreSQL Connection String for xUnit Test Class Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Creating-connection-strings Utilize the `GetUniquePostgreSqlConnectionString()` extension method to generate a PostgreSQL database connection string that is unique to the current xUnit test class, ensuring parallel test execution safety. ```csharp [Fact] public void GetUniquePostgreSqlConnectionStringOk() { //SETUP var config = AppSettings.GetConfiguration(); var orgDbName = new NpgsqlConnectionStringBuilder( config.GetConnectionString(AppSettings.PostgreSqlConnectionString)).Database; //ATTEMPT var con = this.GetUniquePostgreSqlConnectionString(); //VERIFY var newDatabaseName = new NpgsqlConnectionStringBuilder(con).Database; newDatabaseName.ShouldEqual($"{orgDbName}_{GetType().Name}"); } ``` -------------------------------- ### Generate Unique SQL Server Connection String for xUnit Test Class Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Creating-connection-strings Use the `GetUniqueDatabaseConnectionString()` extension method to create a database connection string unique to the current xUnit test class. This prevents conflicts when tests run in parallel. ```csharp [Fact] public void GetTestConnectionStringOk() { //SETUP var config = AppSettings.GetConfiguration(); var orgDbName = new SqlConnectionStringBuilder( config.GetConnectionString(AppSettings.UnitTestConnectionStringName)).InitialCatalog; //ATTEMPT var con = this.GetUniqueDatabaseConnectionString(); //VERIFY var newDatabaseName = new SqlConnectionStringBuilder(con).InitialCatalog; newDatabaseName.ShouldEqual ($"{orgDbName}_{this.GetType().Name}"); } ``` -------------------------------- ### Create Unique SQL Server DB Options Per Test Method Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Generates DbContextOptions for SQL Server, creating a unique database for each test method by appending both class and method names. Ensures complete isolation between test methods. ```csharp public class TestParallelTests { [Fact] public void Method_A_HasIsolatedDatabase() { // DB name: "MyAppTest_TestParallelTests_Method_A_HasIsolatedDatabase" var options = this.CreateUniqueMethodOptions(); using var context = new BookContext(options); context.Database.EnsureClean(); context.Books.Add(new Book { Title = "Book A" }); context.SaveChanges(); context.Books.Count().ShouldEqual(1); } [Fact] public void Method_B_HasIsolatedDatabase() { // DB name: "MyAppTest_TestParallelTests_Method_B_HasIsolatedDatabase" var options = this.CreateUniqueMethodOptions(); using var context = new BookContext(options); context.Database.EnsureClean(); // Completely independent from Method_A — no data contamination. context.Books.Count().ShouldEqual(0); } } ``` -------------------------------- ### Seed Unit Test Database with JSON Data Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Seed-from-Production---Seed-database This C# code demonstrates seeding a unit test database. It ensures the database is created, reads entities from a JSON file, optionally modifies them, and then saves them to the database. ```csharp using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using Xunit; public class BookContext : DbContext { public DbSet Books { get; set; } public BookContext(DbContextOptions options) : base(options) { } } public class Book { public int Id { get; set; } public string Title { get; set; } } public static class SqliteInMemory { public static DbContextOptions CreateOptions() where TContext : DbContext { var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlite("DataSource=:memory:"); return optionsBuilder.Options; } } public static class SeedDataExtensions { public static T ReadSeedDataFromJsonFile(this string fileName) { // Placeholder for actual file reading logic // In a real scenario, this would read a JSON file and deserialize it to type T return default(T); } } public class TestDataResetter { [Fact] public void ExampleSeedDatabase() { //SETUP var options = SqliteInMemory.CreateOptions(); using (var context = new BookContext(options)) { //2a. make sure you have an empty database context.Database.EnsureCreated(); //2b. read the entities back from the JSON file var entities = "ExampleDatabase".ReadSeedDataFromJsonFile>(); //2c. Optionally “tweak” any specific data in the classes that your unit test needs entities.First().Title = "new title"; //2d. Add the data to the database and save context.AddRange(entities); context.SaveChanges(); //ATTEMPT //... run your tests here //VERIFY //... place your asserts here } } } ``` -------------------------------- ### Create Unique Class Options for SQL Server Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQL-Server-databases Use this method to create DbContext options with a unique database name based on the test class. This is recommended for xUnit to avoid parallel test class conflicts. ```csharp var options = this.CreateUniqueClassOptions(); using var context = new EfCoreContext(options) var builder = new SqlConnectionStringBuilder(context.Database. GetDbConnection().ConnectionString); builder.InitialCatalog.ShouldEndWith(this.GetType().Name); ``` -------------------------------- ### Create Unique Method Options for SQL Server Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQL-Server-databases This method creates DbContext options with a unique database name based on the test class and method name. It's generally not needed with xUnit as methods within a class run serially. ```csharp var options = this.CreateUniqueMethodOptions(); using var context = new EfCoreContext(options)) var builder = new SqlConnectionStringBuilder(context.Database.GetDbConnection().ConnectionString); builder.InitialCatalog .ShouldEndWith($"{GetType().Name}.{nameof(TestSqlServerUniqueMethodOk)}" ); ``` -------------------------------- ### Capture EF Core Logs to a List Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Version320---Capture-EF-Core-logging Use `SqliteInMemory.CreateOptionsWithLogging` to capture EF Core logs into a list. This is useful for asserting the generated SQL. ```csharp [Fact] public void TestEfCoreLoggingCheckSqlOutput() { //SETUP var logs = new List(); var options = SqliteInMemory.CreateOptionsWithLogging< BookContext>( log => logs.Add(log)); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); //ATTEMPT context.Books.Count(); //VERIFY logs.Last().Message.ShouldEndWith( "SELECT COUNT(*)\r\nFROM \"Books\" AS \"p\"\nWHERE \"p\".\"SoftDeleted\" = 0"); } } ``` -------------------------------- ### Read Non-Connection String Data Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Accessing-the-appsettings.json-file Demonstrates reading various data types, including integers and nested objects, from the appsettings.json file using direct key access or path-based access for nested values. ```csharp var config = AppSettings.GetConfiguration(); var myInt = config["MyInt"]; //value returned is "1" var myInnerInt = config["MyObject:MyInnerInt"]; //value returns is "2" ``` -------------------------------- ### Populate Test Database from JSON Seed Data Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Use SeedJsonHelpers to read JSON seed data from a file and populate a test database. Supports private setters for entities. ```csharp // --- Step 2: Use the captured JSON in unit tests --- [Fact] public void SeedFromJson_PopulatesTestDatabase() { using var options = SqliteInMemory.CreateOptions(); using var context = new BookContext(options); context.Database.EnsureCreated(); // Reads TestData/SeedData-ExampleDatabase.json var books = "ExampleDatabase".ReadSeedDataFromJsonFile>(); books.ShouldNotBeEmpty(); context.Books.AddRange(books); context.SaveChanges(); context.Books.Count().ShouldEqual(books.Count); context.Books.First().AuthorsLink.ShouldNotBeEmpty(); } ``` -------------------------------- ### Write EF Core logs to xUnit output Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Tools-for-capturing-EF-Core-logging Use this snippet to direct EF Core logs to the xUnit test output window. Ensure your test class accepts ITestOutputHelper in its constructor. ```csharp public class TestOptionsWithLogTo { private readonly ITestOutputHelper _output; public TestOptionsWithLogTo(ITestOutputHelper output) { _output = output; } [Fact] public void TestEfCoreLoggingExampleOfOutputToConsole() { //SETUP var options = SqliteInMemory.CreateOptionsWithLogTo (_output.WriteLine); using var context = new BookContext(options); //... rest of the unit test left out } } ``` -------------------------------- ### Create SQLite In-Memory DbContext Options Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Use this to create disposable DbContext options for an in-memory SQLite database. The connection is automatically closed and the database destroyed when the options object is disposed. appsettings.json is not required. ```csharp // appsettings.json is NOT required for SQLite in-memory tests. // Dispose the options (and its connection) after the test. [Fact] public void SqliteInMemory_BasicCrudTest() { // Create SQLite in-memory options; the using block disposes the connection at the end. using var options = SqliteInMemory.CreateOptions(); using (var context = new BookContext(options)) { context.Database.EnsureCreated(); context.Books.Add(new Book { Title = "EF Core in Action", Price = 35.99m }); context.SaveChanges(); } // Use a fresh DbContext instance to verify the saved data (same connection = same in-memory DB). using (var context = new BookContext(options)) { var book = context.Books.Single(); book.Title.ShouldEqual("EF Core in Action"); // xUnit fluent assertion book.Price.ShouldEqual(35.99m); } } ``` -------------------------------- ### Ensure Clean Database Schema Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Using-SQL-Server-databases This method, copied from EF Core's internal testing code, quickly creates an empty database with the correct schema. It is generally faster than `EnsureDeleted` followed by `EnsureCreated`. ```csharp using var options = this.CreateUniqueClassOptions(); using var context = new BookContext(options); context.Database.EnsureClean(); ``` -------------------------------- ### Ensure Clean Database for SQL Server/PostgreSQL Source: https://github.com/jonpsmith/efcore.testsupport/wiki/Rules-for-tests-using-EF-Core For SQL Server and PostgreSQL, this method provides a quicker alternative to EnsureDeleted and EnsuredCreated for cleaning the database before each test. It ensures the database is empty and the schema matches the current EF Core model. ```csharp EnsureClean() ``` -------------------------------- ### Capture Production Data to JSON with SeedJsonHelpers Source: https://context7.com/jonpsmith/efcore.testsupport/llms.txt Serialize entity graphs from a production DbContext to JSON and save them to a file in the TestData directory. Requires a DataResetter to prepare the data. ```csharp // --- Step 1: Capture production data (run once, manually) --- [RunnableInDebugOnly] public void CaptureProductionDataToJson() { using var prodContext = new BookContext(GetProductionOptions()); var books = prodContext.Books .Include(b => b.AuthorsLink).ThenInclude(a => a.Author) .AsNoTracking() .ToList(); var resetter = new DataResetter(prodContext, new DataResetterConfig()); resetter.ResetKeysEntityAndRelationships(books); // Serializes to TestData/SeedData-ExampleDatabase.json "ExampleDatabase".WriteJsonToJsonFile(books.DefaultSerializeToJson()); } ```