Skip to content

Commit 18d67f1

Browse files
authored
Support IModel being configured once (#473)
1 parent 74ee6dd commit 18d67f1

11 files changed

Lines changed: 133 additions & 48 deletions

File tree

readme.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,25 @@ Enable VerifyEntityFramework once at assembly load time:
2323
<!-- snippet: EnableCore -->
2424
<a id='snippet-enablecore'></a>
2525
```cs
26+
static IModel GetDbModel()
27+
{
28+
var options = new DbContextOptionsBuilder<SampleDbContext>();
29+
options.UseSqlServer("fake");
30+
using var data = new SampleDbContext(options.Options);
31+
return data.Model;
32+
}
33+
2634
[ModuleInitializer]
2735
public static void Init()
2836
{
29-
VerifyEntityFramework.Enable();
37+
var model = GetDbModel();
38+
VerifyEntityFramework.Enable(model);
3039
```
31-
<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>
40+
<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>
3241
<!-- endSnippet -->
3342

43+
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`.
44+
3445

3546
### EF Classic
3647

@@ -68,7 +79,7 @@ builder.UseSqlServer(connection);
6879
builder.EnableRecording();
6980
var data = new SampleDbContext(builder.Options);
7081
```
71-
<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>
82+
<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>
7283
<!-- endSnippet -->
7384

7485
`EnableRecording` should only be called in the test context.
@@ -91,12 +102,12 @@ await data.SaveChangesAsync();
91102
EfRecording.StartRecording();
92103

93104
await data.Companies
94-
.Where(x => x.Content == "Title")
105+
.Where(_ => _.Content == "Title")
95106
.ToListAsync();
96107

97108
await Verify(data.Companies.Count());
98109
```
99-
<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>
110+
<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>
100111
<!-- endSnippet -->
101112

102113
Will result in the following verified file:
@@ -144,7 +155,7 @@ await data.SaveChangesAsync();
144155
EfRecording.StartRecording();
145156

146157
await data.Companies
147-
.Where(x => x.Content == "Title")
158+
.Where(_ => _.Content == "Title")
148159
.ToListAsync();
149160

150161
var entries = EfRecording.FinishRecording();
@@ -155,7 +166,7 @@ await Verify(new
155166
sql = entries
156167
});
157168
```
158-
<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>
169+
<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>
159170
<!-- endSnippet -->
160171

161172

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

182193
await using var data2 = new SampleDbContext(builder.Options);
183194
await data2.Companies
184-
.Where(x => x.Content == "Title")
195+
.Where(_ => _.Content == "Title")
185196
.ToListAsync();
186197

187198
await Verify(data2.Companies.Count());
188199
```
189-
<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>
200+
<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>
190201
<!-- endSnippet -->
191202

192203
<!-- snippet: CoreTests.MultiDbContexts.verified.txt -->
@@ -377,10 +388,10 @@ This test:
377388
<a id='snippet-queryable'></a>
378389
```cs
379390
var queryable = data.Companies
380-
.Where(x => x.Content == "value");
391+
.Where(_ => _.Content == "value");
381392
await Verify(queryable);
382393
```
383-
<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>
394+
<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>
384395
<!-- endSnippet -->
385396

386397
Will result in the following verified file:
@@ -426,7 +437,7 @@ await Verify(data.AllData())
426437
serializer =>
427438
serializer.TypeNameHandling = TypeNameHandling.Objects);
428439
```
429-
<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>
440+
<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>
430441
<!-- endSnippet -->
431442

432443
Will result in the following verified file with all data in the database:
@@ -506,7 +517,7 @@ public async Task IgnoreNavigationProperties()
506517
Company = company
507518
};
508519
await Verify(employee)
509-
.IgnoreNavigationProperties(data);
520+
.IgnoreNavigationProperties();
510521
}
511522
```
512523
<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>
@@ -520,9 +531,9 @@ public async Task IgnoreNavigationProperties()
520531
```cs
521532
var options = DbContextOptions();
522533
using var data = new SampleDbContext(options);
523-
VerifyEntityFramework.IgnoreNavigationProperties(data.Model);
534+
VerifyEntityFramework.IgnoreNavigationProperties();
524535
```
525-
<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>
536+
<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>
526537
<!-- endSnippet -->
527538

528539

@@ -542,7 +553,7 @@ To be able to use [WebApplicationFactory](https://docs.microsoft.com/en-us/dotne
542553
.Options);
543554
});
544555
```
545-
<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>
556+
<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>
546557
<!-- endSnippet -->
547558

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

559570
var entries = EfRecording.FinishRecording(testName);
560571
```
561-
<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>
572+
<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>
562573
<!-- endSnippet -->
563574

564575
The results will not be automatically included in verified file so it will have to be verified manually:
@@ -572,7 +583,7 @@ await Verify(new
572583
sql = entries
573584
});
574585
```
575-
<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>
586+
<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>
576587
<!-- endSnippet -->
577588

578589

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project>
33
<PropertyGroup>
44
<NoWarn>CS1591;CS0649;CS8632;EF1001</NoWarn>
5-
<Version>9.2.0</Version>
5+
<Version>9.3.0</Version>
66
<AssemblyVersion>1.0.0</AssemblyVersion>
77
<PackageTags>EntityFramework, Verify</PackageTags>
88
<Description>Extends Verify (https://github.com/VerifyTests/Verify) to allow verification of EntityFramework bits.</Description>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
Content: employee
3+
}

src/Verify.EntityFramework.Tests/CoreTests.cs

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,30 @@ public async Task IgnoreNavigationProperties()
7171

7272
await using var data = new SampleDbContext(options);
7373

74+
var company = new Company
75+
{
76+
Content = "company"
77+
};
78+
var employee = new Employee
79+
{
80+
Content = "employee",
81+
Company = company
82+
};
83+
await Verify(employee)
84+
.IgnoreNavigationProperties();
85+
}
86+
87+
#endregion
88+
89+
#region IgnoreNavigationPropertiesExplicit
90+
91+
[Test]
92+
public async Task IgnoreNavigationPropertiesExplicit()
93+
{
94+
var options = DbContextOptions();
95+
96+
await using var data = new SampleDbContext(options);
97+
7498
var company = new Company
7599
{
76100
Content = "company"
@@ -90,6 +114,17 @@ void IgnoreNavigationPropertiesGlobal()
90114
{
91115
#region IgnoreNavigationPropertiesGlobal
92116

117+
var options = DbContextOptions();
118+
using var data = new SampleDbContext(options);
119+
VerifyEntityFramework.IgnoreNavigationProperties();
120+
121+
#endregion
122+
}
123+
124+
void IgnoreNavigationPropertiesGlobalExplicit()
125+
{
126+
#region IgnoreNavigationPropertiesGlobalExplicit
127+
93128
var options = DbContextOptions();
94129
using var data = new SampleDbContext(options);
95130
VerifyEntityFramework.IgnoreNavigationProperties(data.Model);
@@ -213,7 +248,7 @@ public async Task Queryable()
213248
#region Queryable
214249

215250
var queryable = data.Companies
216-
.Where(x => x.Content == "value");
251+
.Where(_ => _.Content == "value");
217252
await Verify(queryable);
218253

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

228263
var query = data.Set<Company>()
229-
.Select(x => x.Id);
264+
.Select(_ => _.Id);
230265
await Verify(query);
231266
}
232267

@@ -236,7 +271,7 @@ public async Task NestedQueryable()
236271
var database = await DbContextBuilder.GetDatabase("NestedQueryable");
237272
var data = database.Context;
238273
var queryable = data.Companies
239-
.Where(x => x.Content == "value");
274+
.Where(_ => _.Content == "value");
240275
await Verify(queryable);
241276
}
242277

@@ -286,7 +321,7 @@ public async Task MultiRecording()
286321
{
287322
var s = i.ToString();
288323
await data.Companies
289-
.Where(x => x.Content == s)
324+
.Where(_ => _.Content == s)
290325
.ToListAsync();
291326
}
292327

@@ -325,7 +360,7 @@ public async Task MultiDbContexts()
325360

326361
await using var data2 = new SampleDbContext(builder.Options);
327362
await data2.Companies
328-
.Where(x => x.Content == "Title")
363+
.Where(_ => _.Content == "Title")
329364
.ToListAsync();
330365

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

353388
await data.Companies
354-
.Where(x => x.Content == "Title")
389+
.Where(_ => _.Content == "Title")
355390
.ToListAsync();
356391

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

371-
using var connection = new SqliteConnection($"Data Source={testName};Mode=Memory;Cache=Shared");
406+
await using var connection = new SqliteConnection($"Data Source={testName};Mode=Memory;Cache=Shared");
372407
await connection.OpenAsync();
373408

374409
var factory = new CustomWebApplicationFactory(testName);
@@ -413,7 +448,7 @@ await Verify(new
413448

414449
class CustomWebApplicationFactory : WebApplicationFactory<Startup>
415450
{
416-
readonly string testName;
451+
string testName;
417452

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

437472
protected override IHostBuilder CreateHostBuilder() =>
438473
Host.CreateDefaultBuilder()
439-
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
474+
.ConfigureWebHostDefaults(builder => builder.UseStartup<Startup>());
440475
}
441476

442477
public class Startup
@@ -453,7 +488,7 @@ public void Configure(IApplicationBuilder app)
453488
app.UseRouting();
454489

455490
app.UseEndpoints(endpoints
456-
=> endpoints.MapGet("/companies", async (SampleDbContext data) => await data.Companies.ToListAsync()));
491+
=> endpoints.MapGet("/companies", (SampleDbContext data) => data.Companies.ToListAsync()));
457492
}
458493
}
459494

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

477512
await data.Companies
478-
.Where(x => x.Content == "Title")
513+
.Where(_ => _.Content == "Title")
479514
.ToListAsync();
480515

481516
var entries = EfRecording.FinishRecording();

src/Verify.EntityFramework.Tests/ModuleInitializer.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1-
public static class ModuleInitializer
1+
using Microsoft.EntityFrameworkCore.Metadata;
2+
3+
public static class ModuleInitializer
24
{
35
#region EnableCore
46

7+
static IModel GetDbModel()
8+
{
9+
var options = new DbContextOptionsBuilder<SampleDbContext>();
10+
options.UseSqlServer("fake");
11+
using var data = new SampleDbContext(options.Options);
12+
return data.Model;
13+
}
14+
515
[ModuleInitializer]
616
public static void Init()
717
{
8-
VerifyEntityFramework.Enable();
18+
var model = GetDbModel();
19+
VerifyEntityFramework.Enable(model);
920

1021
#endregion
1122

src/Verify.EntityFramework.Tests/Snippets/DataContext/SampleDbContext.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ public SampleDbContext(DbContextOptions options) :
99
{
1010
}
1111

12-
protected override void OnModelCreating(ModelBuilder modelBuilder)
12+
protected override void OnModelCreating(ModelBuilder builder)
1313
{
14-
modelBuilder.Entity<Company>()
14+
builder.Entity<Company>()
1515
.HasMany(c => c.Employees)
1616
.WithOne(e => e.Company)
1717
.IsRequired();
18-
modelBuilder.Entity<Employee>();
18+
builder.Entity<Employee>();
1919
}
2020
}

src/Verify.EntityFramework/Converters/TrackerConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static void HandleDeleted(List<EntityEntry> entries, VerifyJsonWriter writer)
3939
static void HandleAdded(List<EntityEntry> entries, VerifyJsonWriter writer)
4040
{
4141
var added = entries
42-
.Where(x => x.State == EntityState.Added)
42+
.Where(_ => _.State == EntityState.Added)
4343
.ToList();
4444
if (!added.Any())
4545
{

src/Verify.EntityFramework/LogCommandInterceptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class LogCommandInterceptor :
33
{
44
static AsyncLocal<State?> asyncLocal = new();
55
static ConcurrentDictionary<string, List<LogEntry>> namedEvents = new(StringComparer.OrdinalIgnoreCase);
6-
readonly string? identifier;
6+
string? identifier;
77

88
public static void Start() => asyncLocal.Value = new();
99
public static void Start(string identifier) => namedEvents.GetOrAdd(identifier, _ => new());

0 commit comments

Comments
 (0)