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
75 changes: 63 additions & 12 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Enable VerifyEntityFramework once at assembly load time:
```cs
VerifyEntityFramework.Enable();
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L370-L374' 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/CoreTests.cs#L472-L476' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablecore' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down Expand Up @@ -58,7 +58,7 @@ builder.UseSqlServer(connection);
builder.EnableRecording();
var data = new SampleDbContext(builder.Options);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L230-L237' 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#L239-L246' 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 Down Expand Up @@ -86,7 +86,7 @@ await data.Companies

await Verify(data.Companies.Count());
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L310-L327' 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#L319-L336' 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 @@ -143,7 +143,7 @@ await Verify(new
sql = entries
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L336-L359' 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#L438-L461' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordingspecific' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down Expand Up @@ -174,7 +174,7 @@ await data2.Companies

await Verify(data2.Companies.Count());
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L279-L301' 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#L288-L310' 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 @@ -241,7 +241,7 @@ public async Task Added()
await Verify(data.ChangeTracker);
}
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L8-L24' title='Snippet source file'>snippet source</a> | <a href='#snippet-added' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L17-L33' 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:
Expand Down Expand Up @@ -275,15 +275,15 @@ public async Task Deleted()
var options = DbContextOptions();

await using var data = new SampleDbContext(options);
data.Add(new Company {Content = "before"});
data.Add(new Company { Content = "before" });
await data.SaveChangesAsync();

var company = data.Companies.Single();
data.Companies.Remove(company);
await Verify(data.ChangeTracker);
}
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L26-L42' title='Snippet source file'>snippet source</a> | <a href='#snippet-deleted' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L35-L51' title='Snippet source file'>snippet source</a> | <a href='#snippet-deleted' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file:
Expand Down Expand Up @@ -327,7 +327,7 @@ public async Task Modified()
await Verify(data.ChangeTracker);
}
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L44-L63' title='Snippet source file'>snippet source</a> | <a href='#snippet-modified' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L53-L72' title='Snippet source file'>snippet source</a> | <a href='#snippet-modified' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file:
Expand Down Expand Up @@ -362,7 +362,7 @@ var queryable = data.Companies
.Where(x => x.Content == "value");
await Verify(queryable);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L209-L215' 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#L218-L224' 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 @@ -410,7 +410,7 @@ await Verify(data.AllData())
serializer =>
serializer.TypeNameHandling = TypeNameHandling.Objects));
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L190-L199' 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#L199-L208' 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 @@ -494,9 +494,60 @@ public async Task IgnoreNavigationProperties()
x => x.IgnoreNavigationProperties(data));
}
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L65-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-ignorenavigationproperties' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L74-L97' title='Snippet source file'>snippet source</a> | <a href='#snippet-ignorenavigationproperties' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## WebApplicationFactory

To be able to use [WebApplicationFactory](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing.webapplicationfactory-1) for [integration testing](https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests)
an identifier must be used to be able to retrive the recorded commands. Start by enable recording with a unique identifier, for example the test name or a GUID:

<!-- snippet: EnableRecordingWithIdentifier -->
<a id='snippet-enablerecordingwithidentifier'></a>
```cs
.ConfigureTestServices(services =>
{
services.AddScoped<DbContextOptions<SampleDbContext>>(_ =>
{
return new DbContextOptionsBuilder<SampleDbContext>()
.EnableRecording(testName)
.UseSqlite($"Data Source={testName};Mode=Memory;Cache=Shared")
.Options;
});
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L394-L405' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecordingwithidentifier' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Then use the same identifer for recording:

<!-- snippet: RecordWithIdentifier -->
<a id='snippet-recordwithidentifier'></a>
```cs
var httpClient = factory.CreateClient();

EfRecording.StartRecording(testName);

var companies = await httpClient.GetFromJsonAsync<Company[]>("/companies");

var entries = EfRecording.FinishRecording(testName);
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L364-L372' 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:

<!-- snippet: VerifyRecordedCommandsWithIdentifier -->
<a id='snippet-verifyrecordedcommandswithidentifier'></a>
```cs
await Verify(new
{
target = companies!.Length,
sql = entries
});
```
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L374-L380' title='Snippet source file'>snippet source</a> | <a href='#snippet-verifyrecordedcommandswithidentifier' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Icon

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
target: 1,
sql: [
{
Type: ReaderExecutedAsync,
Text:
SELECT "c"."Id", "c"."Content"
FROM "Companies" AS "c"
}
]
}
110 changes: 106 additions & 4 deletions src/Verify.EntityFramework.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
using Microsoft.EntityFrameworkCore;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using VerifyTests.EntityFramework;

[TestFixture]
[Parallelizable(ParallelScope.All)]
public class CoreTests
{
#region Added
Expand Down Expand Up @@ -31,7 +40,7 @@ public async Task Deleted()
var options = DbContextOptions();

await using var data = new SampleDbContext(options);
data.Add(new Company {Content = "before"});
data.Add(new Company { Content = "before" });
await data.SaveChangesAsync();

var company = data.Companies.Single();
Expand Down Expand Up @@ -158,7 +167,7 @@ public Task ShouldIgnoreDbContext() =>
Factory = new SampleDbContext(new DbContextOptions<SampleDbContext>())
});

class MyDbContextFactory: IDbContextFactory<SampleDbContext>
class MyDbContextFactory : IDbContextFactory<SampleDbContext>
{
public SampleDbContext CreateDbContext() =>
throw new NotImplementedException();
Expand Down Expand Up @@ -222,7 +231,7 @@ public async Task NestedQueryable()
var data = database.Context;
var queryable = data.Companies
.Where(x => x.Content == "value");
await Verify(new {queryable});
await Verify(new { queryable });
}

void Build(string connection)
Expand Down Expand Up @@ -327,6 +336,99 @@ await data.Companies
#endregion
}

[DatapointSource]
public IEnumerable<int> runs = Enumerable.Range(0, 5);

[Theory]
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 connection.OpenAsync();

var factory = new CustomWebApplicationFactory(testName);

using (var scope = factory.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<SampleDbContext>();

await context.Database.EnsureCreatedAsync();

context.Add(new Company { Id = 1, Content = "Foo" });

await context.SaveChangesAsync();
}

#region RecordWithIdentifier
var httpClient = factory.CreateClient();

EfRecording.StartRecording(testName);

var companies = await httpClient.GetFromJsonAsync<Company[]>("/companies");

var entries = EfRecording.FinishRecording(testName);
#endregion

#region VerifyRecordedCommandsWithIdentifier
await Verify(new
{
target = companies!.Length,
sql = entries
});
#endregion
}

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

public CustomWebApplicationFactory(string testName)
{
this.testName = testName;
}

protected override void ConfigureWebHost(IWebHostBuilder builder) =>
builder
#region EnableRecordingWithIdentifier
.ConfigureTestServices(services =>
{
services.AddScoped<DbContextOptions<SampleDbContext>>(_ =>
{
return new DbContextOptionsBuilder<SampleDbContext>()
.EnableRecording(testName)
.UseSqlite($"Data Source={testName};Mode=Memory;Cache=Shared")
.Options;
});
});
#endregion

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

public class Startup
Comment thread
OskarKlintrot marked this conversation as resolved.
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddDbContext<SampleDbContext>(builder =>
{
builder.UseInMemoryDatabase("");
});
}

public void Configure(IApplicationBuilder app)
{
app.UseRouting();

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

[Test]
public async Task RecordingSpecific()
{
Expand Down
Loading