Skip to content

The in-memory fixture the documentation recommends for tests failed at the first save - #203

Merged
dmitrat merged 1 commit into
mainfrom
ef-in-memory-fixture
Aug 15, 2026
Merged

The in-memory fixture the documentation recommends for tests failed at the first save#203
dmitrat merged 1 commit into
mainfrom
ef-in-memory-fixture

Conversation

@dmitrat

@dmitrat dmitrat commented Aug 15, 2026

Copy link
Copy Markdown
Owner

First of the fixes planned in Docs/FIX-PLAN-FROM-SITE-FINDINGS-2026-08-15.md, and the one that costs a user most: the testing path three pages of the documentation recommend does not survive its first SaveChanges.

Measured

EnsureCreated: True
THREW DbUpdateException
  inner WitDbException: Table 'Items' not found

EnsureCreated() reports success and the very next operation cannot find the table it just made.

Why

UseWitDbInMemory() configured the context with a connection string. An in-memory database is private to its connection — WitDbConnection.cs:115 says so in as many words — and EF opens and closes a connection for every operation (WitDatabaseCreator does it explicitly around EnsureCreated). So every operation got a fresh, empty database.

The fix

The provider creates the connection, opens it, and hands the open connection to the extension through the WithConnection path that already existed for UseWitDb(connection). EF does not close a connection it did not open, so the store outlives an operation. Same recipe SQLite's provider documents, same reason.

The July audit sized this at two days and listed two routes — named shared memory, or a no-op Close() for in-memory in WitRelationalConnection. Supplying an open connection is a third, and it is an afternoon.

Ownership is stated rather than left to be discovered. Nothing disposes that connection, so the database lives as long as the options object and is collected with it — right for a test fixture, wrong for anything long-lived. It is in the XML comment, and an overload taking a WitDbConnection the caller owns sits beside it.

The guards, and what each is for

InMemoryTests carried the note "these tests verify configuration and tracking, not full database execution", and that sentence was the defect: eighteen cases over this fixture and not one of them wrote a row.

AnInMemoryFixtureKeepsItsRowsAcrossOperationsTest EnsureCreatedSaveChanges → read back in the same context → read back in a second context. Red before the fix, and red again with only the Open() removed — both parts of the fix have their own red
ControlTwoInMemoryFixturesAreTwoDatabasesTest the control that decides whether the fix is the RIGHT one. Sharing one store globally would pass the round trip perfectly and make every test in a suite a neighbour of every other
ControlAnInMemoryFixtureWritesNoFileTest the creator decides "in memory" by reading the connection string; a fix that changed it would quietly start leaving databases on disk

UseWitDbInMemoryConfiguresExtensionTest asserted ConnectionString == "Data Source=:memory:", which was true and was the defect. It asserts the open connection now, with the reason in its own remarks — RelationalOptionsExtension.ConnectionString is null in the connection-supplied shape by design, as it is for every other provider.

EF 593 cases, up from 590.

🤖 Generated with Claude Code

…t the first save

UseWitDbInMemory() configured the context with a connection STRING, and an in-memory
database is private to its connection - WitDbConnection.cs:115 says so in as many words.
Entity Framework opens and closes a connection for every operation, so every operation got
a fresh empty database. Measured: EnsureCreated() returns true and the very next
SaveChanges throws DbUpdateException -> WitDbException: Table 'Items' not found. The
fixture has never been able to save a row.

The provider now creates the connection, OPENS it, and hands the open connection to the
extension through the WithConnection path that was already there for UseWitDb(connection).
EF does not close a connection it did not open, so the store outlives an operation. This is
the recipe SQLite's provider documents, and for the same reason. The July audit sized this
at two days and listed two routes - named shared memory, or a no-op Close for in-memory in
WitRelationalConnection; supplying an open connection is a third one and it is an
afternoon.

Nothing disposes that connection, so the database lives as long as the options object and
is collected with it. That is right for a test fixture and wrong for anything long-lived,
so it is written into the XML comment rather than left to be discovered, and an overload
taking a WitDbConnection the caller owns sits beside it for when the lifetime has to be in
somebody's hands.

InMemoryTests carried the note "these tests verify configuration and tracking, not full
database execution", and that sentence was the defect: eighteen cases over the fixture and
not one of them wrote a row. Three cases now do. The round trip is red before the fix with
Table 'Entities' not found, and so it is with only the Open() removed - both parts of the
fix have their own red. Two controls decide whether the fix is the right one: two fixtures
must remain two databases, because sharing one store globally would pass the round trip
perfectly and make every test in a suite a neighbour of every other; and an in-memory
fixture must still write no file, because the creator decides "in memory" by reading the
connection string and a fix that changed it would quietly leave databases on disk.

UseWitDbInMemoryConfiguresExtensionTest asserted the connection string, which was true and
was the defect. It asserts the open connection now, and says why in its own remarks.

EF 593 cases, up from 590.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dmitrat
dmitrat merged commit 825fcd3 into main Aug 15, 2026
1 check passed
@dmitrat
dmitrat deleted the ef-in-memory-fixture branch August 15, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant