Verify.EntityFramework
Extends Verify to allow verification of EntityFramework bits.
Install / Use
/learn @VerifyTests/Verify.EntityFrameworkREADME
<img src="/src/icon.png" height="30px"> Verify.EntityFramework
Extends Verify to allow snapshot testing with EntityFramework.<!-- singleLineInclude: intro. path: /docs/intro.include.md -->
See Milestones for release notes.
Sponsors
Entity Framework Extensions<!-- include: sponsors. path: /docs/sponsors.include.md -->
Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.
Developed using JetBrains IDEs
NuGet
- https://nuget.org/packages/Verify.EntityFramework/
- https://nuget.org/packages/Verify.EntityFrameworkClassic/
Enable
Enable VerifyEntityFramework once at assembly load time:
EF Core
<!-- snippet: EnableCore --><a id='snippet-EnableCore'></a>
static IModel GetDbModel()
{
var options = new DbContextOptionsBuilder<SampleDbContext>();
options.UseSqlServer("fake");
using var data = new SampleDbContext(options.Options);
return data.Model;
}
[ModuleInitializer]
public static void Init()
{
var model = GetDbModel();
VerifyEntityFramework.Initialize(model);
}
<sup><a href='/src/Verify.EntityFramework.Tests/ModuleInitializer.cs#L5-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-EnableCore' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->The GetDbModel pattern allows an instance of the IModel to be stored for use when IgnoreNavigationProperties is called inside tests. This is optional, and instead can be passed explicitly to IgnoreNavigationProperties.
EF Classic
<!-- snippet: EnableClassic --><a id='snippet-EnableClassic'></a>
[ModuleInitializer]
public static void Init() =>
VerifyEntityFrameworkClassic.Initialize();
<sup><a href='/src/Verify.EntityFrameworkClassic.Tests/ModuleInitializer.cs#L3-L9' title='Snippet source file'>snippet source</a> | <a href='#snippet-EnableClassic' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Recording
Recording allows all commands executed by EF to be captured and then (optionally) verified.
Enable
Call EfRecording.EnableRecording() on DbContextOptionsBuilder.
<a id='snippet-EnableRecording'></a>
var builder = new DbContextOptionsBuilder<SampleDbContext>();
builder.UseSqlServer(connection);
builder.EnableRecording();
var data = new SampleDbContext(builder.Options);
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L358-L365' title='Snippet source file'>snippet source</a> | <a href='#snippet-EnableRecording' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->EnableRecording should only be called in the test context.
Usage
To start recording call EfRecording.StartRecording(). The results will be automatically included in verified file.
<a id='snippet-Recording'></a>
var company = new Company
{
Name = "Title"
};
data.Add(company);
await data.SaveChangesAsync();
Recording.Start();
await data
.Companies
.Where(_ => _.Name == "Title")
.ToListAsync();
await Verify();
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L457-L475' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Will result in the following verified file:
<!-- snippet: CoreTests.RecordingTest.verified.txt --><a id='snippet-CoreTests.RecordingTest.verified.txt'></a>
{
ef: {
Type: ReaderExecutedAsync,
HasTransaction: false,
Text:
select c.Id,
c.Name
from Companies as c
where c.Name = N'Title'
}
}
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.RecordingTest.verified.txt#L1-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.RecordingTest.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Sql entries can be explicitly read using EfRecording.FinishRecording, optionally filtered, and passed to Verify:
<a id='snippet-RecordingSpecific'></a>
var company = new Company
{
Name = "Title"
};
data.Add(company);
await data.SaveChangesAsync();
Recording.Start();
await data
.Companies
.Where(_ => _.Name == "Title")
.ToListAsync();
var entries = Recording.Stop();
//TODO: optionally filter the results
await Verify(
new
{
target = data.Companies.Count(),
entries
});
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L682-L707' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->DbContext spanning
StartRecording can be called on different DbContext instances (built from the same options) and the results will be aggregated.
<a id='snippet-MultiDbContexts'></a>
var builder = new DbContextOptionsBuilder<SampleDbContext>();
builder.UseSqlServer(connectionString);
builder.EnableRecording();
await using var data1 = new SampleDbContext(builder.Options);
Recording.Start();
var company = new Company
{
Name = "Title"
};
data1.Add(company);
await data1.SaveChangesAsync();
await using var data2 = new SampleDbContext(builder.Options);
await data2
.Companies
.Where(_ => _.Name == "Title")
.ToListAsync();
await Verify();
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L425-L448' title='Snippet source file'>snippet source</a> | <a href='#snippet-MultiDbContexts' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet --> <!-- snippet: CoreTests.MultiDbContexts.verified.txt --><a id='snippet-CoreTests.MultiDbContexts.verified.txt'></a>
{
ef: [
{
Type: ReaderExecutedAsync,
HasTransaction: false,
Parameters: {
@p0 (Int32): 0,
@p1 (String): Title
},
Text:
set implicit_transactions off;
set nocount on;
insert into Companies (Id, Name)
values (@p0, @p1)
},
{
Type: ReaderExecutedAsync,
HasTransaction: false,
Text:
select c.Id,
c.Name
from Companies as c
where c.Name = N'Title'
}
]
}
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.MultiDbContexts.verified.txt#L1-L28' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.MultiDbContexts.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Disabling Recording for an instance
<!-- snippet: RecordingDisableForInstance --><a id='snippet-RecordingDisableForInstance'></a>
var company = new Company
{
Name = "Title"
};
data.Add(company);
await data.SaveChangesAsync();
Recording.Start();
await data
.Companies
.Where(_ => _.Name == "Title")
.ToListAsync();
data.DisableRecording();
await data
.Companies
.Where(_ => _.Name == "Disabled")
.ToListAsync();
await Verify();
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L553-L576' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingDisableForInstance' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet --> <!-- snippet: CoreTests.RecordingDisabledTest.verified.txt --><a id='snippet-CoreTests.RecordingDisabledTest.verified.txt'></a>
{
ef: {
Type: ReaderExecutedAsync,
HasTransaction: false,
Text:
select c.Id,
c.Name
from Companies as c
where c.Name = N'Title'
}
}
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.RecordingDisabledTest.verified.txt#L1-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.RecordingDisabledTest.verified.txt' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->ChangeTracking
Added, deleted, and Modified entities can be verified by performing changes on a DbContext and then verifying the instance of ChangeTracking. This approach leverages the EntityFramework ChangeTracker.
Added entity
This test:
<!-- snippet: Added --><a id='snippet-Added'></a>
[Test]
public async Task Added()
{
var options = DbContextOptions();
await using var data = new SampleDbContext(options);
var company = new Company
{
Name = "company name"
};
data.Add(company);
await Verify(data.ChangeTracker);
}
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L61-L77' title='Snippet source file'>snippet source</a> | <a href='#snippet-Added' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->Will result in the following verified file:
<!-- snippet: CoreTests.Added.verified.txt --><a id='snippet-CoreTests.Added.verified.txt'><
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR

