2020-01-06 11:53:20 +03:00
# <img src="/src/icon.png" height="30px"> Verify.EntityFramework
2020-01-06 07:58:10 +03:00
2020-05-06 09:57:51 +03:00
[![Build status ](https://ci.appveyor.com/api/projects/status/g6njwv0aox62atu0?svg=true )](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
2020-01-06 11:53:20 +03:00
[![NuGet Status ](https://img.shields.io/nuget/v/Verify.EntityFramework.svg )](https://www.nuget.org/packages/Verify.EntityFramework/)
2020-02-19 02:19:19 +03:00
[![NuGet Status ](https://img.shields.io/nuget/v/Verify.EntityFrameworkClassic.svg )](https://www.nuget.org/packages/Verify.EntityFrameworkClassic/)
2020-01-06 07:58:10 +03:00
2020-05-06 02:48:20 +03:00
Extends [Verify ](https://github.com/VerifyTests/Verify ) to allow verification of EntityFramework bits.
2020-01-06 07:58:10 +03:00
2020-07-25 03:00:13 +03:00
Support is available via a [Tidelift Subscription ](https://tidelift.com/subscription/pkg/nuget-verify?utm_source=nuget-verify&utm_medium=referral&utm_campaign=enterprise ).
2020-01-06 07:58:10 +03:00
2020-07-26 04:53:24 +03:00
< a href = 'https://dotnetfoundation.org' alt = 'Part of the .NET Foundation' > < img src = 'https://raw.githubusercontent.com/VerifyTests/Verify/master/docs/dotNetFoundation.svg' height = '30px' > < / a > < br >
Part of the < a href = 'https://dotnetfoundation.org' alt = '' > .NET Foundation< / a >
2020-01-06 07:58:10 +03:00
<!-- toc -->
## Contents
* [Usage ](#usage )
2020-04-16 01:34:23 +03:00
* [EF Core ](#ef-core )
* [EF Classic ](#ef-classic )
2020-08-19 10:02:41 +03:00
* [Recording ](#recording )
2020-01-07 05:08:39 +03:00
* [ChangeTracking ](#changetracking )
2020-01-17 12:42:09 +03:00
* [Queryable ](#queryable )
2020-04-16 01:34:23 +03:00
* [EF Core ](#ef-core-1 )
* [EF Classic ](#ef-classic-1 )
2020-08-20 07:48:49 +03:00
* [Security contact information ](#security-contact-information )<!-- endToc -->
2020-01-06 07:58:10 +03:00
## NuGet package
2020-02-19 02:19:19 +03:00
* https://nuget.org/packages/Verify.EntityFramework/
* https://nuget.org/packages/Verify.EntityFrameworkClassic/
2020-01-06 07:58:10 +03:00
## Usage
2020-01-06 13:38:28 +03:00
Enable VerifyEntityFramewok once at assembly load time:
2020-01-06 07:58:10 +03:00
2020-04-16 01:34:23 +03:00
### EF Core
<!-- snippet: EnableCore -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-enablecore' > < / a >
2020-01-06 07:58:10 +03:00
```cs
2020-01-06 11:53:20 +03:00
VerifyEntityFramework.Enable();
2020-01-06 07:58:10 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L265-L269' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-enablecore' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-04-16 01:34:23 +03:00
### EF Classic
<!-- snippet: EnableClassic -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-enableclassic' > < / a >
2020-02-18 09:12:51 +03:00
```cs
2020-02-19 01:44:24 +03:00
VerifyEntityFrameworkClassic.Enable();
2020-02-18 09:12:51 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFrameworkClassic.Tests/ClassicTests.cs#L139-L143' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-enableclassic' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-08-19 10:02:41 +03:00
### Recording
2020-08-20 00:16:22 +03:00
Recording allows all commands executed by EF to be captured and then (optionally) verified.
2020-08-19 10:11:16 +03:00
2020-08-19 10:02:41 +03:00
#### Enable
2020-09-12 15:21:00 +03:00
Call `SqlRecording.EnableRecording()` on `DbContextOptionsBuilder` .
2020-08-19 10:02:41 +03:00
2020-08-20 00:31:56 +03:00
<!-- snippet: EnableRecording -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-enablerecording' > < / a >
2020-08-20 00:31:56 +03:00
```cs
var builder = new DbContextOptionsBuilder< SampleDbContext > ();
builder.UseSqlServer(connection);
builder.EnableRecording();
var data = new SampleDbContext(builder.Options);
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L155-L162' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-enablerecording' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-08-19 10:02:41 +03:00
2020-09-12 15:21:00 +03:00
`EnableRecording` should only be called in the test context.
2020-08-20 14:01:33 +03:00
2020-08-19 10:02:41 +03:00
2020-09-12 15:21:00 +03:00
#### Usage
2020-08-19 10:11:16 +03:00
2020-09-12 15:21:00 +03:00
On the `DbContext` call `SqlRecording.StartRecording()` to start recording.
2020-08-19 10:11:16 +03:00
2020-08-19 10:02:41 +03:00
<!-- snippet: Recording -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-recording' > < / a >
2020-08-19 10:02:41 +03:00
```cs
[Test]
public async Task Recording()
{
var database = await DbContextBuilder.GetDatabase("Recording");
var data = database.Context;
var company = new Company
{
Content = "Title"
};
data.Add(company);
await data.SaveChangesAsync();
2020-09-10 08:43:13 +03:00
SqlRecording.StartRecording();
2020-08-19 10:02:41 +03:00
await data.Companies
.Where(x => x.Content == "Title")
.ToListAsync();
2020-09-10 08:43:13 +03:00
await Verifier.Verify(data.Companies.Count());
2020-08-19 10:02:41 +03:00
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L228-L251' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-recording' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-08-19 10:02:41 +03:00
Will result in the following verified file:
<!-- snippet: CoreTests.Recording.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.Recording.verified.txt' > < / a >
2020-08-19 10:02:41 +03:00
```txt
2020-09-10 08:43:13 +03:00
{
target: '5',
sql: [
{
Type: 'ReaderExecutedAsync',
Text: "SELECT [c].[Id], [c].[Content]
2020-08-19 10:02:41 +03:00
FROM [Companies] AS [c]
WHERE [c].[Content] = N'Title'"
2020-09-10 08:43:13 +03:00
},
{
Type: 'ReaderExecuted',
Text: 'SELECT COUNT(*)
FROM [Companies] AS [c]'
}
]
}
2020-08-19 10:02:41 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.Recording.verified.txt#L1-L16' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.Recording.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 07:58:10 +03:00
2020-08-20 14:01:33 +03:00
#### DbContext spanning
2020-09-12 15:21:00 +03:00
`StartRecording` can be called on different DbContext instances (built from the same options) and the results will be aggregated.
2020-08-20 14:01:33 +03:00
<!-- snippet: MultiDbContexts -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-multidbcontexts' > < / a >
2020-08-20 14:01:33 +03:00
```cs
var builder = new DbContextOptionsBuilder< SampleDbContext > ();
builder.UseSqlServer(connectionString);
builder.EnableRecording();
await using var data1 = new SampleDbContext(builder.Options);
2020-09-10 08:43:13 +03:00
SqlRecording.StartRecording();
2020-08-20 14:01:33 +03:00
var company = new Company
{
Content = "Title"
};
data1.Add(company);
await data1.SaveChangesAsync();
await using var data2 = new SampleDbContext(builder.Options);
await data2.Companies
.Where(x => x.Content == "Title")
.ToListAsync();
2020-09-10 08:43:13 +03:00
await Verifier.Verify(data2.Companies.Count());
2020-08-20 14:01:33 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L203-L225' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-multidbcontexts' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 14:01:33 +03:00
<!-- endSnippet -->
<!-- snippet: CoreTests.MultiDbContexts.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.MultiDbContexts.verified.txt' > < / a >
2020-08-20 14:01:33 +03:00
```txt
2020-09-10 08:43:13 +03:00
{
target: '5',
sql: [
{
Type: 'ReaderExecutedAsync',
HasTransaction: true,
Parameters: {
@p0: 0,
@p1: 'Title'
},
Text: 'SET NOCOUNT ON;
2020-08-20 14:01:33 +03:00
INSERT INTO [Companies] ([Id], [Content])
VALUES (@p0, @p1 );'
2020-09-10 08:43:13 +03:00
},
{
Type: 'ReaderExecutedAsync',
Text: "SELECT [c].[Id], [c].[Content]
2020-08-20 14:01:33 +03:00
FROM [Companies] AS [c]
WHERE [c].[Content] = N'Title'"
2020-09-10 08:43:13 +03:00
},
{
Type: 'ReaderExecuted',
Text: 'SELECT COUNT(*)
FROM [Companies] AS [c]'
}
]
}
2020-08-20 14:01:33 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.MultiDbContexts.verified.txt#L1-L27' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.MultiDbContexts.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 14:01:33 +03:00
<!-- endSnippet -->
2020-01-07 05:08:39 +03:00
### ChangeTracking
2020-08-19 06:33:30 +03:00
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 ](https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.changetracker ).
2020-01-07 05:08:39 +03:00
#### Added entity
2020-01-06 07:58:10 +03:00
2020-01-06 13:38:28 +03:00
This test:
<!-- snippet: Added -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-added' > < / a >
2020-01-06 13:38:28 +03:00
```cs
2020-06-07 10:06:09 +03:00
[Test]
2020-01-06 13:38:28 +03:00
public async Task Added()
{
var options = DbContextOptions();
2020-04-03 03:32:46 +03:00
await using var data = new SampleDbContext(options);
2020-07-07 06:40:02 +03:00
var company = new Company
{
Content = "before"
};
data.Add(company);
2020-08-19 06:32:40 +03:00
await Verifier.Verify(data.ChangeTracker);
2020-01-06 13:38:28 +03:00
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L13-L29' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-added' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 13:38:28 +03:00
Will result in the following verified file:
2020-01-06 07:58:10 +03:00
2020-04-16 01:34:23 +03:00
<!-- snippet: CoreTests.Added.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.Added.verified.txt' > < / a >
2020-01-06 13:38:28 +03:00
```txt
{
Added: {
Company: {
2020-01-06 13:39:54 +03:00
Id: 0,
Content: 'before'
2020-01-06 13:38:28 +03:00
}
}
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.Added.verified.txt#L1-L8' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.Added.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 13:38:28 +03:00
2020-01-07 05:08:39 +03:00
#### Deleted entity
2020-01-06 07:58:10 +03:00
This test:
2020-01-06 13:38:28 +03:00
<!-- snippet: Deleted -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-deleted' > < / a >
2020-01-06 13:38:28 +03:00
```cs
2020-06-07 10:06:09 +03:00
[Test]
2020-01-06 13:38:28 +03:00
public async Task Deleted()
{
var options = DbContextOptions();
2020-04-03 03:32:46 +03:00
await using var data = new SampleDbContext(options);
data.Add(new Company {Content = "before"});
await data.SaveChangesAsync();
2020-01-06 13:38:28 +03:00
2020-04-03 03:32:46 +03:00
var company = data.Companies.Single();
data.Companies.Remove(company);
2020-08-19 06:32:40 +03:00
await Verifier.Verify(data.ChangeTracker);
2020-01-06 13:38:28 +03:00
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L31-L47' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-deleted' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 07:58:10 +03:00
Will result in the following verified file:
2020-04-16 01:34:23 +03:00
<!-- snippet: CoreTests.Deleted.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.Deleted.verified.txt' > < / a >
2020-01-06 13:38:28 +03:00
```txt
{
Deleted: {
Company: {
Id: 0
}
}
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.Deleted.verified.txt#L1-L7' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.Deleted.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 13:38:28 +03:00
2020-01-07 05:08:39 +03:00
#### Modified entity
2020-01-06 13:38:28 +03:00
This test:
<!-- snippet: Modified -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-modified' > < / a >
2020-01-06 13:38:28 +03:00
```cs
2020-06-07 10:06:09 +03:00
[Test]
2020-01-06 13:38:28 +03:00
public async Task Modified()
{
var options = DbContextOptions();
2020-04-03 03:32:46 +03:00
await using var data = new SampleDbContext(options);
2020-07-07 06:40:02 +03:00
var company = new Company
{
Content = "before"
};
2020-04-03 03:32:46 +03:00
data.Add(company);
await data.SaveChangesAsync();
2020-01-06 13:38:28 +03:00
2020-04-03 03:32:46 +03:00
data.Companies.Single().Content = "after";
2020-08-19 06:32:40 +03:00
await Verifier.Verify(data.ChangeTracker);
2020-01-06 13:38:28 +03:00
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L49-L68' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-modified' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 07:58:10 +03:00
2020-01-06 13:38:28 +03:00
Will result in the following verified file:
2020-04-16 01:34:23 +03:00
<!-- snippet: CoreTests.Modified.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.Modified.verified.txt' > < / a >
2020-02-18 09:12:51 +03:00
```txt
{
Modified: {
Company: {
Id: 0,
Content: {
Original: 'before',
Current: 'after'
}
}
}
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.Modified.verified.txt#L1-L11' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.Modified.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 07:58:10 +03:00
2020-01-06 15:56:57 +03:00
### Queryable
This test:
<!-- snippet: Queryable -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-queryable' > < / a >
2020-01-06 15:56:57 +03:00
```cs
2020-06-07 10:06:09 +03:00
[Test]
2020-01-06 15:56:57 +03:00
public async Task Queryable()
{
var database = await DbContextBuilder.GetDatabase("Queryable");
2020-04-03 03:32:46 +03:00
var data = database.Context;
2020-07-07 06:40:02 +03:00
var queryable = data.Companies
.Where(x => x.Content == "value");
2020-06-07 10:06:09 +03:00
await Verifier.Verify(queryable);
2020-01-06 15:56:57 +03:00
}
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.cs#L129-L141' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-queryable' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 15:56:57 +03:00
Will result in the following verified file:
2020-04-16 01:34:23 +03:00
### EF Core
<!-- snippet: CoreTests.Queryable.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-CoreTests.Queryable.verified.txt' > < / a >
2020-02-18 09:12:51 +03:00
```txt
2020-07-07 06:40:02 +03:00
SELECT [c].[Id], [c].[Content]
FROM [Companies] AS [c]
WHERE [c].[Content] = N'value'
2020-02-18 09:12:51 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFramework.Tests/CoreTests.Queryable.verified.txt#L1-L3' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-CoreTests.Queryable.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-04-16 01:34:23 +03:00
### EF Classic
<!-- snippet: ClassicTests.Queryable.verified.txt -->
2020-10-11 00:25:07 +03:00
< a id = 'snippet-ClassicTests.Queryable.verified.txt' > < / a >
2020-04-16 01:34:23 +03:00
```txt
2020-07-07 06:40:02 +03:00
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Content] AS [Content]
FROM [dbo].[Companies] AS [Extent1]
WHERE N'value' = [Extent1].[Content]
2020-04-16 01:34:23 +03:00
```
2020-10-11 00:25:07 +03:00
< sup > < a href = '/src/Verify.EntityFrameworkClassic.Tests/ClassicTests.Queryable.verified.txt#L1-L5' title = 'Snippet source file' > snippet source< / a > | < a href = '#snippet-ClassicTests.Queryable.verified.txt' title = 'Start of snippet' > anchor< / a > < / sup >
2020-08-20 07:48:49 +03:00
<!-- endSnippet -->
2020-01-06 15:56:57 +03:00
2020-01-17 12:42:09 +03:00
## Security contact information
2020-01-27 03:46:18 +03:00
To report a security vulnerability, use the [Tidelift security contact ](https://tidelift.com/security ). Tidelift will coordinate the fix and disclosure.
2020-01-17 12:42:09 +03:00
2020-01-06 07:58:10 +03:00
## Icon
2020-01-06 13:46:25 +03:00
[Database ](https://thenounproject.com/term/database/310841/ ) designed by [Creative Stall ](https://thenounproject.com/creativestall/ ) from [The Noun Project ](https://thenounproject.com/creativepriyanka ).