testing
Testing
EF Core test infrastructure, patterns, and workflows for unit, specification, and functional tests.
Test Categories
Unit Tests (test/EFCore.Tests/, test/EFCore.Relational.Tests/, test/EFCore.{Provider}.Tests/)
Isolated logic tests. Build models via *TestHelpers.Instance.CreateConventionBuilder(), resolve services from CreateContextServices(). No database needed.
Specification Tests (provider-agnostic abstract bases)
Define WHAT to test (LINQ queries, expected results). Can't be run directly — provider tests override to verify HOW (generated SQL).
- Core →
test/EFCore.Specification.Tests/ - Relational →
test/EFCore.Relational.Specification.Tests/
Functional Tests (test/EFCore.{Provider}.FunctionalTests/)
Concrete provider tests inheriting specification tests. Most include SQL baseline assertions.
Test Class Hierarchy (Query Example)
QueryTestBase<TFixture> # Core
└─ NorthwindWhereQueryTestBase<TFixture> # Specification
└─ NorthwindWhereQueryRelationalTestBase<TFixture> # Relational specification
└─ NorthwindWhereQuerySqlServerTest # Provider (asserts SQL)
Provider override pattern:
public override async Task Where_simple(bool async)
{
await base.Where_simple(async); // runs LINQ + asserts results
AssertSql("""..."""); // asserts provider-specific SQL
}
TestHelpers Hierarchy
TestHelpers (abstract) # EFCore.Specification.Tests
├─ InMemoryTestHelpers # non-relational
└─ RelationalTestHelpers (abstract) # EFCore.Relational.Specification.Tests
├─ SqlServerTestHelpers
└─ SqliteTestHelpers
Key methods: CreateConventionBuilder(), CreateContextServices(model), CreateOptions()
Fixtures
SharedStoreFixtureBase
Many tests share one database. Creates TestStore + pooled DbContextFactory in InitializeAsync(). Seeds data once. Use for read-heavy tests (e.g., Northwind query tests).
NonSharedModelTestBase
Each test gets a fresh model/store. Call InitializeAsync<TContext>(onModelCreating, seed, ...) per test. Use for tests needing unique schemas.
SQL Baseline Assertions
TestSqlLoggerFactory captures SQL. AssertSql("""...""") compares against expected. Set EF_TEST_REWRITE_BASELINES=1 to auto-rewrite baselines via Roslyn.
Workflow: Adding New Tests
- Specification test: Add to
EFCore.Specification.Tests(core) orEFCore.Relational.Specification.Tests(relational) - Provider override: Override in
EFCore.{Provider}.FunctionalTestswithAssertSql() - Unit test: Add to
EFCore.{Provider}.Tests - Run with
EF_TEST_REWRITE_BASELINES=1to capture initial baselines - When testing cross-platform code (e.g., file paths, path separators), verify the fix works on both Windows and Linux/macOS
Common Pitfalls
| Pitfall | Solution |
|---|---|
| SQL or Compiled model baseline mismatch | Set EF_TEST_REWRITE_BASELINES=1 and re-run |
Check_all_tests_overridden fails |
Override new base test in provider test class |