Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implementation details for EF Core test infrastructure. Use when changing test fixtures, SQL baseline assertions, test helpers, the test class hierarchy, or when adding new tests.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-02 | ✗→✓ | ▲ Improved | — | — |
| case-22 | ✗→✓ | ▲ Improved | — | — |
| case-04 | ✗→✓ | ▲ Improved | — | — |
| case-10 | ✗→✓ | ▲ Improved | — | — |
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.
Define WHAT to test (LINQ queries, expected results). Can't be run directly — provider tests override to verify HOW (generated SQL).
test/EFCore.Specification.Tests/test/EFCore.Relational.Specification.Tests/test/EFCore.{Provider}.FunctionalTests/)Concrete provider tests inheriting specification tests. Most include SQL baseline assertions.
QueryTestBase<TFixture> # Core
└─ NorthwindWhereQueryTestBase<TFixture> # Specification
└─ NorthwindWhereQueryRelationalTestBase<TFixture> # Relational specification
└─ NorthwindWhereQuerySqlServerTest # Provider (asserts SQL)Provider override pattern:
csharppublic override async Task Where_simple(bool async) { await base.Where_simple(async); // runs LINQ + asserts results AssertSql("""..."""); // asserts provider-specific SQL }
TestHelpers (abstract) # EFCore.Specification.Tests
├─ InMemoryTestHelpers # non-relational
└─ RelationalTestHelpers (abstract) # EFCore.Relational.Specification.Tests
├─ SqlServerTestHelpers
└─ SqliteTestHelpersKey methods: CreateConventionBuilder(), CreateContextServices(model), CreateOptions()
Many tests share one database. Creates TestStore + pooled DbContextFactory in InitializeAsync(). Seeds data once. Use for read-heavy tests (e.g., Northwind query tests).
Each test gets a fresh model/store. Call InitializeAsync<TContext>(onModelCreating, seed, ...) per test. Use for tests needing unique schemas.
TestSqlLoggerFactory captures SQL. AssertSql("""...""") compares against expected. Set EF_TEST_REWRITE_BASELINES=1 to auto-rewrite baselines via Roslyn.
EFCore.Specification.Tests (core) or EFCore.Relational.Specification.Tests (relational)EFCore.{Provider}.FunctionalTests) that inherits the base with provider-appropriate assertions.EFCore.{Provider}.TestsEF_TEST_REWRITE_BASELINES=1 to capture initial baselines--no-build) to ensure code changes are picked up| Pitfall | Solution | |---------|----------| | Baseline mismatch (SQL or compiled model) | Re-run with EF_TEST_REWRITE_BASELINES=1 | | Check_all_tests_overridden fails | Override the new test in every inheriting provider class | | SQL Server feature missing at lower compat level | Gate with [SqlServerCondition(...)]|
When invoking the test DLL via dotnet exec (e.g. to isolate a single test method without rebuilding through dotnet test), always append --filter-not-trait category=failing --ignore-exit-code 8:
pwshdotnet exec ./Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests.dll ` --filter-method '*MigrationsSqlServerTest.Create_json_index_over_whole_complex_collection' ` --filter-not-trait category=failing --ignore-exit-code 8
These flags mirror what test/Directory.Build.props passes via TestingPlatformCommandLineArguments.
Don't add --no-build unless the test assembly was built in the immediate previous step.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +36 percentage points is the difference between those two pass rates over the 22 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.