Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,25 @@ Enable VerifyEntityFramework once at assembly load time:
<!-- snippet: EnableCore -->
<a id='snippet-enablecore'></a>
```cs
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()
{
VerifyEntityFramework.Enable();
var model = GetDbModel();
VerifyEntityFramework.Enable(model);
```
<sup><a href='/src/Verify.EntityFramework.Tests/ModuleInitializer.cs#L3-L10' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablecore' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/ModuleInitializer.cs#L5-L21' 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

Expand Down Expand Up @@ -68,7 +79,7 @@ builder.UseSqlServer(connection);
builder.EnableRecording();
var data = new SampleDbContext(builder.Options);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L245-L252' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecording' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L280-L287' 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.
Expand All @@ -91,12 +102,12 @@ await data.SaveChangesAsync();
EfRecording.StartRecording();

await data.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

await Verify(data.Companies.Count());
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L342-L359' title='Snippet source file'>snippet source</a> | <a href='#snippet-recording' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L377-L394' 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:
Expand Down Expand Up @@ -144,7 +155,7 @@ await data.SaveChangesAsync();
EfRecording.StartRecording();

await data.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

var entries = EfRecording.FinishRecording();
Expand All @@ -155,7 +166,7 @@ await Verify(new
sql = entries
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L466-L489' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordingspecific' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L501-L524' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordingspecific' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand All @@ -181,12 +192,12 @@ await data1.SaveChangesAsync();

await using var data2 = new SampleDbContext(builder.Options);
await data2.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

await Verify(data2.Companies.Count());
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L311-L333' title='Snippet source file'>snippet source</a> | <a href='#snippet-multidbcontexts' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L346-L368' title='Snippet source file'>snippet source</a> | <a href='#snippet-multidbcontexts' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

<!-- snippet: CoreTests.MultiDbContexts.verified.txt -->
Expand Down Expand Up @@ -377,10 +388,10 @@ This test:
<a id='snippet-queryable'></a>
```cs
var queryable = data.Companies
.Where(x => x.Content == "value");
.Where(_ => _.Content == "value");
await Verify(queryable);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L213-L219' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryable' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L248-L254' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryable' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file:
Expand Down Expand Up @@ -426,7 +437,7 @@ await Verify(data.AllData())
serializer =>
serializer.TypeNameHandling = TypeNameHandling.Objects);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L197-L204' title='Snippet source file'>snippet source</a> | <a href='#snippet-alldata' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L232-L239' title='Snippet source file'>snippet source</a> | <a href='#snippet-alldata' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file with all data in the database:
Expand Down Expand Up @@ -506,7 +517,7 @@ public async Task IgnoreNavigationProperties()
Company = company
};
await Verify(employee)
.IgnoreNavigationProperties(data);
.IgnoreNavigationProperties();
}
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L65-L87' title='Snippet source file'>snippet source</a> | <a href='#snippet-ignorenavigationproperties' title='Start of snippet'>anchor</a></sup>
Expand All @@ -520,9 +531,9 @@ public async Task IgnoreNavigationProperties()
```cs
var options = DbContextOptions();
using var data = new SampleDbContext(options);
VerifyEntityFramework.IgnoreNavigationProperties(data.Model);
VerifyEntityFramework.IgnoreNavigationProperties();
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L91-L97' title='Snippet source file'>snippet source</a> | <a href='#snippet-ignorenavigationpropertiesglobal' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L115-L121' title='Snippet source file'>snippet source</a> | <a href='#snippet-ignorenavigationpropertiesglobal' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand All @@ -542,7 +553,7 @@ To be able to use [WebApplicationFactory](https://docs.microsoft.com/en-us/dotne
.Options);
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L424-L435' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecordingwithidentifier' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L459-L470' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecordingwithidentifier' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Then use the same identifier for recording:
Expand All @@ -558,7 +569,7 @@ var companies = await httpClient.GetFromJsonAsync<Company[]>("/companies");

var entries = EfRecording.FinishRecording(testName);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L391-L401' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordwithidentifier' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L426-L436' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordwithidentifier' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The results will not be automatically included in verified file so it will have to be verified manually:
Expand All @@ -572,7 +583,7 @@ await Verify(new
sql = entries
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L403-L411' title='Snippet source file'>snippet source</a> | <a href='#snippet-verifyrecordedcommandswithidentifier' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L438-L446' title='Snippet source file'>snippet source</a> | <a href='#snippet-verifyrecordedcommandswithidentifier' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<NoWarn>CS1591;CS0649;CS8632;EF1001</NoWarn>
<Version>9.2.0</Version>
<Version>9.3.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<PackageTags>EntityFramework, Verify</PackageTags>
<Description>Extends Verify (https://github.com/VerifyTests/Verify) to allow verification of EntityFramework bits.</Description>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
Content: employee
}
57 changes: 46 additions & 11 deletions src/Verify.EntityFramework.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,30 @@ public async Task IgnoreNavigationProperties()

await using var data = new SampleDbContext(options);

var company = new Company
{
Content = "company"
};
var employee = new Employee
{
Content = "employee",
Company = company
};
await Verify(employee)
.IgnoreNavigationProperties();
}

#endregion

#region IgnoreNavigationPropertiesExplicit

[Test]
public async Task IgnoreNavigationPropertiesExplicit()
{
var options = DbContextOptions();

await using var data = new SampleDbContext(options);

var company = new Company
{
Content = "company"
Expand All @@ -90,6 +114,17 @@ void IgnoreNavigationPropertiesGlobal()
{
#region IgnoreNavigationPropertiesGlobal

var options = DbContextOptions();
using var data = new SampleDbContext(options);
VerifyEntityFramework.IgnoreNavigationProperties();

#endregion
}

void IgnoreNavigationPropertiesGlobalExplicit()
{
#region IgnoreNavigationPropertiesGlobalExplicit

var options = DbContextOptions();
using var data = new SampleDbContext(options);
VerifyEntityFramework.IgnoreNavigationProperties(data.Model);
Expand Down Expand Up @@ -213,7 +248,7 @@ public async Task Queryable()
#region Queryable

var queryable = data.Companies
.Where(x => x.Content == "value");
.Where(_ => _.Content == "value");
await Verify(queryable);

#endregion
Expand All @@ -226,7 +261,7 @@ public async Task SetSelect()
var data = database.Context;

var query = data.Set<Company>()
.Select(x => x.Id);
.Select(_ => _.Id);
await Verify(query);
}

Expand All @@ -236,7 +271,7 @@ public async Task NestedQueryable()
var database = await DbContextBuilder.GetDatabase("NestedQueryable");
var data = database.Context;
var queryable = data.Companies
.Where(x => x.Content == "value");
.Where(_ => _.Content == "value");
await Verify(queryable);
}

Expand Down Expand Up @@ -286,7 +321,7 @@ public async Task MultiRecording()
{
var s = i.ToString();
await data.Companies
.Where(x => x.Content == s)
.Where(_ => _.Content == s)
.ToListAsync();
}

Expand Down Expand Up @@ -325,7 +360,7 @@ public async Task MultiDbContexts()

await using var data2 = new SampleDbContext(builder.Options);
await data2.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

await Verify(data2.Companies.Count());
Expand All @@ -351,7 +386,7 @@ public async Task Recording()
EfRecording.StartRecording();

await data.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

await Verify(data.Companies.Count());
Expand All @@ -368,7 +403,7 @@ public async Task RecordingWebApplicationFactory(int run)
// Not actually the test name, the variable name is for README.md to make sense
var testName = nameof(RecordingWebApplicationFactory) + run;

using var connection = new SqliteConnection($"Data Source={testName};Mode=Memory;Cache=Shared");
await using var connection = new SqliteConnection($"Data Source={testName};Mode=Memory;Cache=Shared");
await connection.OpenAsync();

var factory = new CustomWebApplicationFactory(testName);
Expand Down Expand Up @@ -413,7 +448,7 @@ await Verify(new

class CustomWebApplicationFactory : WebApplicationFactory<Startup>
{
readonly string testName;
string testName;

public CustomWebApplicationFactory(string testName) =>
this.testName = testName;
Expand All @@ -436,7 +471,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) =>

protected override IHostBuilder CreateHostBuilder() =>
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
.ConfigureWebHostDefaults(builder => builder.UseStartup<Startup>());
}

public class Startup
Expand All @@ -453,7 +488,7 @@ public void Configure(IApplicationBuilder app)
app.UseRouting();

app.UseEndpoints(endpoints
=> endpoints.MapGet("/companies", async (SampleDbContext data) => await data.Companies.ToListAsync()));
=> endpoints.MapGet("/companies", (SampleDbContext data) => data.Companies.ToListAsync()));
}
}

Expand All @@ -475,7 +510,7 @@ public async Task RecordingSpecific()
EfRecording.StartRecording();

await data.Companies
.Where(x => x.Content == "Title")
.Where(_ => _.Content == "Title")
.ToListAsync();

var entries = EfRecording.FinishRecording();
Expand Down
15 changes: 13 additions & 2 deletions src/Verify.EntityFramework.Tests/ModuleInitializer.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
public static class ModuleInitializer
using Microsoft.EntityFrameworkCore.Metadata;

public static class ModuleInitializer
{
#region EnableCore

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()
{
VerifyEntityFramework.Enable();
var model = GetDbModel();
VerifyEntityFramework.Enable(model);

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ public SampleDbContext(DbContextOptions options) :
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
protected override void OnModelCreating(ModelBuilder builder)
{
modelBuilder.Entity<Company>()
builder.Entity<Company>()
.HasMany(c => c.Employees)
.WithOne(e => e.Company)
.IsRequired();
modelBuilder.Entity<Employee>();
builder.Entity<Employee>();
}
}
2 changes: 1 addition & 1 deletion src/Verify.EntityFramework/Converters/TrackerConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static void HandleDeleted(List<EntityEntry> entries, VerifyJsonWriter writer)
static void HandleAdded(List<EntityEntry> entries, VerifyJsonWriter writer)
{
var added = entries
.Where(x => x.State == EntityState.Added)
.Where(_ => _.State == EntityState.Added)
.ToList();
if (!added.Any())
{
Expand Down
2 changes: 1 addition & 1 deletion src/Verify.EntityFramework/LogCommandInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class LogCommandInterceptor :
{
static AsyncLocal<State?> asyncLocal = new();
static ConcurrentDictionary<string, List<LogEntry>> namedEvents = new(StringComparer.OrdinalIgnoreCase);
readonly string? identifier;
string? identifier;

public static void Start() => asyncLocal.Value = new();
public static void Start(string identifier) => namedEvents.GetOrAdd(identifier, _ => new());
Expand Down
Loading