|
6 | 6 | [](https://www.nuget.org/packages/EntityFrameworkCore.AutoFixture/) |
7 | 7 | [](https://licenses.nuget.org/MIT) |
8 | 8 |
|
9 | | -**EntityFrameworkCore.AutoFixture** is the logical product of [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) in-memory providers and [AutoFixture](https://github.com/AutoFixture/AutoFixture). |
| 9 | +**EntityFrameworkCore.AutoFixture** is a library that helps with testing code that uses [Entity Framework](https://docs.microsoft.com/en-us/ef/core/), by reducing the boilerplate code necessary to set up database contexts (see [examples](#examples)), with the help of [AutoFixture](https://github.com/AutoFixture/AutoFixture). |
10 | 10 |
|
11 | | -Using **EntityFrameworkCore.AutoFixture** you can greatly reduce the boilerplate work necessary to unit test code that uses **Entity Framework Core** database contexts (see [examples](#examples)). You'll appreciate this library if you are already using **AutoFixture** as your auto-mocking container. |
| 11 | +Unlike other libraries for faking EF contexts, **EntityFrameworkCore.AutoFixture** does not use mocking frameworks or |
| 12 | +dynamic proxies in to create database contexts, instead it uses the actual database [providers](https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/). This ensures the tests will behave a lot more similar to the code in the production environment, with little to no effort. |
12 | 13 |
|
13 | | -**EntityFrameworkCore.AutoFixture** extens **AutoFixture** with the ability to create fully functional `DbContext` instances, with very little setup code. |
| 14 | +#### :warning: .NET Standard 2.0 in EF Core v3.0.x :warning: |
14 | 15 |
|
15 | | -Unlike other libraries for faking EF contexts, **EntityFrameworkCore.AutoFixture** does not use mocking frameworks or dynamic proxies in order to create `DbContext` instances, instead it uses the Microsoft's own in-memory [providers](https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/) for EF Core. This allows to make less assumptions (read as: mock setups) in your tests about how the `DbContext` will behave in the real environment. |
| 16 | +Entity Framework Core `v3.0.0` - `v3.0.3` are targeting `netstandard2.1`, which means they are not compatible with |
| 17 | +target frameworks that support at most `netstandard2.0` (`>= net47` and `netcoreapp2.1`). |
| 18 | +Versions after `v3.1` are targeting `netstandard2.0`. If you've encountered this issue consider upgrading to a later |
| 19 | +version of Entity Framework Core. |
16 | 20 |
|
17 | 21 | ## Features |
18 | 22 |
|
19 | | -**EntityFrameworkCore.AutoFixture** offers three customizations to aid your unit testing workflow: |
| 23 | +**EntityFrameworkCore.AutoFixture** offers three customizations to help your unit testing workflow: |
20 | 24 |
|
21 | | -- `InMemoryContextCustomization` - customizes fixtures to use the In-Memory database provider when creating _DbContext_ instances |
22 | | -- `SqliteContextCustomization` - customizes fixtures to use the SQLite database provider when creating _DbContext_ instances. |
23 | | - By default the customization will create contexts for an in-memory _connection string_ (i.e. `DataSource=:memory:`). This can be changed by providing the fixture a predefined `SqliteConnection` instance. |
24 | | -- `DbContextCustomization` - serves as the base customization for the other two implementations. The customization can be used, in more advanced scenarios, when you want to extend the fixtures with your own specimen builders. |
| 25 | +- `InMemoryCustomization` - Customizes fixtures to create contexts using the In-Memory database provider |
| 26 | +- `SqliteCustomization` - Customizes fixtures to create contexts using the SQLite database provider |
| 27 | +- `DbContextCustomization` - A base class for database provider customizations. Can be used, in more advanced scenarios, for example, to extend the existing functionality or create customizations for other providers. |
25 | 28 |
|
26 | 29 | ## Examples |
27 | 30 |
|
28 | | -The examples below demonstrate, the possible ways of using the library in [xUnit](https://github.com/xunit/xunit) test projects, both with `[Fact]` and `[Theory]` tests. |
| 31 | +The examples below demonstrate, the possible ways of using the library in [xUnit](https://xunit.net) test projects, both with `[Fact]` and `[Theory]` tests. |
29 | 32 |
|
30 | | -The library is not limited to `xUnit` and can be used with other testing frameworks like `NUnit` and `MSTest`, since it only provides a few `Customization` implementations. |
| 33 | +The library is not limited to `xUnit` and can be used with other testing frameworks like [NUnit](https://nunit.org) and [MSTest](https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest), since it only provides the customizations. |
31 | 34 |
|
32 | 35 | ### Using In-Memory database provider |
33 | 36 |
|
| 37 | +By default this customization will configure all contexts to use the [in-memory](https://docs.microsoft.com/en-us/ef/core/testing/testing-without-the-database#in-memory-provider) database provider for Enity Framework, and will create the database, giving you a ready to use context. |
| 38 | + |
34 | 39 | ```csharp |
35 | 40 | [Fact] |
36 | | -public void SaveChanges_ShouldCreateCustomerRecord() |
| 41 | +public async Task CanSavesCustomers() |
37 | 42 | { |
38 | | - var fixture = new Fixture().Customize(new InMemoryContextCustomization()); |
39 | | - using (var context = fixture.Create<TestDbContext>()) |
40 | | - { |
41 | | - context.Database.EnsureCreated(); |
| 43 | + // Arrange |
| 44 | + var fixture = new Fixture().Customize(new InMemoryCustomization()); |
| 45 | + var context = fixture.Create<TestDbContext>(); |
42 | 46 |
|
43 | | - context.Customers.Add(new Customer("John Doe")); |
44 | | - context.SaveChanges(); |
| 47 | + // Act |
| 48 | + context.Customers.Add(new Customer("Jane Smith")); |
| 49 | + await context.SaveChangesAsync(); |
45 | 50 |
|
46 | | - context.Customers.Should().Contain(x => x.Name == "John Doe"); |
47 | | - } |
| 51 | + // Assert |
| 52 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
48 | 53 | } |
49 | 54 | ``` |
50 | 55 |
|
51 | | -The next example uses a custom `AutoData` attribute `AutoDomainDataWithInMemoryContext` that customizes the fixture with the same customization as in the example above. This helps abstract away even more setup code. The attribute implementation can be found the sources of the test projects. |
| 56 | +With the default configuration, the custmization will set the store name to `TestDatabase` and will suffix it with a random string to ensure the name is unique. After the context is created it will run `Database.EnsureCreated()` to create the database. |
| 57 | + |
| 58 | +This behavior can be changed by setting the corresponding values in the customizaiton initializer. |
52 | 59 |
|
53 | 60 | ```csharp |
54 | | -[Theory] |
55 | | -[AutoDomainDataWithInMemoryContext] |
56 | | -public async Task SaveChangesAsync_ShouldCreateCustomerRecord(TestDbContext context) |
| 61 | +[Fact] |
| 62 | +public async Task CanSavesCustomers() |
57 | 63 | { |
58 | | - await using (context) |
| 64 | + // Arrange |
| 65 | + var fixture = new Fixture().Customize(new InMemoryCustomization |
59 | 66 | { |
60 | | - await context.Database.EnsureCreatedAsync(); |
| 67 | + DatabaseName = "MyCoolDatabase", // Sets the store name to "MyCoolDatabase" |
| 68 | + UseUniqueNames = false, // No suffix for store names. All contexts will connect to same store |
| 69 | + OnCreate = OnCreateAction.Migrate // Will run Database.Migrate() |
| 70 | + // Use OnCreateAction.None to skip creating the database |
| 71 | + }); |
| 72 | + var context = fixture.Create<TestDbContext>(); |
| 73 | + |
| 74 | + // Act |
| 75 | + context.Customers.Add(new Customer("Jane Smith")); |
| 76 | + await context.SaveChangesAsync(); |
| 77 | + |
| 78 | + // Assert |
| 79 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 80 | +} |
| 81 | +``` |
61 | 82 |
|
62 | | - context.Customers.Add(new Customer("Jane Smith")); |
63 | | - await context.SaveChangesAsync(); |
| 83 | +To encapsulate the configuration and remove even more of the boilerplate, use the `AutoData` attributes offered by AutoFixture. |
64 | 84 |
|
65 | | - context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 85 | +```csharp |
| 86 | +public class PersistenceDataAttribute : AutoDataAttribute |
| 87 | +{ |
| 88 | + public PersistenceDataAttribute() |
| 89 | + : base(() => new Fixture().Customize(new InMemoryCustomization { |
| 90 | + UseUniqueNames = false, |
| 91 | + OnCreate = OnCreateAction.Migrate |
| 92 | + })) |
| 93 | + { |
66 | 94 | } |
67 | 95 | } |
68 | 96 | ``` |
69 | 97 |
|
70 | | -For more examples using the In-Memory database provider see the [docs](./using-in-memory-provider). |
| 98 | +```csharp |
| 99 | +[Theory, PersistenceData] // Notice the data attribute |
| 100 | +public async Task CanUseGeneratedContext(TestDbContext context) |
| 101 | +{ |
| 102 | + // Arrange & Act |
| 103 | + context.Customers.Add(new Customer("Jane Smith")); |
| 104 | + await context.SaveChangesAsync(); |
| 105 | + |
| 106 | + // Assert |
| 107 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 108 | +} |
| 109 | +``` |
| 110 | + |
| 111 | +For more information about using the `InMemoryCustomization` see this [page](./using-in-memory-provider). |
71 | 112 |
|
72 | 113 | ### Using SQLite database provider |
73 | 114 |
|
74 | | -When using the SQLite database provider be sure to also _freeze_ / _inject_ the `SqliteConnection` instance, in order to be able to control its lifetime. |
75 | | -Otherwise the connection might close, which might in its turn fail your tests. |
| 115 | +By default this customization will configure all contexts to use the [SQLite](https://docs.microsoft.com/en-us/ef/core/testing/testing-without-the-database#sqlite-in-memory) database provider for Enity Framework, and will automatically create the database, giving you a ready to use context. |
76 | 116 |
|
77 | 117 | ```csharp |
78 | | -[Theory] |
79 | | -[AutoDomainDataWithSqliteContext] |
80 | | -public void Customize_ShouldProvideSqliteContext([Frozen] SqliteConnection connection, |
81 | | - TestDbContext context, Item item, Customer customer) |
| 118 | +[Fact] |
| 119 | +public async Task CanUseGeneratedContext() |
82 | 120 | { |
83 | | - using (connection) |
84 | | - using (context) |
85 | | - { |
86 | | - connection.Open(); |
87 | | - context.Database.EnsureCreated(); |
88 | | - context.Items.Add(item); |
| 121 | + // Arrange |
| 122 | + var fixture = new Fixture().Customize(new SqliteCustomization()); |
| 123 | + var context = fixture.Create<TestDbContext>(); |
89 | 124 |
|
90 | | - context.Customers.Add(customer); |
91 | | - context.SaveChanges(); |
| 125 | + // Act |
| 126 | + context.Customers.Add(new Customer("Jane Smith")); |
| 127 | + await context.SaveChangesAsync(); |
92 | 128 |
|
93 | | - customer.Order(item, 5); |
94 | | - context.SaveChanges(); |
| 129 | + // Assert |
| 130 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 131 | +} |
| 132 | +``` |
95 | 133 |
|
96 | | - context.Orders.Should().Contain(x => x.CustomerId == customer.Id && x.ItemId == item.Id); |
| 134 | +With the default configuration, the custmization will set the connection string to `Data Source=:memory:`, will open the connection and after the context is created it will run `Database.EnsureCreated()` to create the database. |
| 135 | + |
| 136 | +This behavior can be changed by setting the corresponding values in the customizaiton initializer. |
| 137 | + |
| 138 | +```csharp |
| 139 | +[Fact] |
| 140 | +public async Task CanSavesCustomers() |
| 141 | +{ |
| 142 | + // Arrange |
| 143 | + var fixture = new Fixture().Customize(new SqliteCustomization |
| 144 | + { |
| 145 | + ConnectionString = "Data Source=MyDatabase.sqlite;Cache=Shared;", // Sets the connection string to connect to a file |
| 146 | + AutoOpenConnection = false, // Disables opening the connection by default. Affects all SqliteConnection instances. |
| 147 | + OnCreate = OnCreateAction.None // Will to skip creating the database |
| 148 | + // Use OnCreateAction.EnsureCreated to run Database.EnsureCreated() automatically |
| 149 | + // Use OnCreateAction.Migrate to run Database.Migrate() automatically |
| 150 | + }); |
| 151 | + var connection = fixture.Freeze<SqliteConnection>(); |
| 152 | + var context = fixture.Create<TestDbContext>(); |
| 153 | + connection.Open(); |
| 154 | + context.Database.Migrate(); |
| 155 | + |
| 156 | + // Act |
| 157 | + context.Customers.Add(new Customer("Jane Smith")); |
| 158 | + await context.SaveChangesAsync(); |
| 159 | + |
| 160 | + // Assert |
| 161 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 162 | +} |
| 163 | +``` |
| 164 | + |
| 165 | +To encapsulate the configuration and remove even more of the boilerplate, use the `AutoData` attributes offered by AutoFixture. |
| 166 | + |
| 167 | +```csharp |
| 168 | +public class PersistenceDataAttribute : AutoDataAttribute |
| 169 | +{ |
| 170 | + public PersistenceDataAttribute() |
| 171 | + : base(() => new Fixture().Customize(new SqliteCustomization { |
| 172 | + ConnectionString = "Data Source=MyDatabase;Mode=Memory;Cache=Shared;" |
| 173 | + OnCreate = OnCreateAction.Migrate |
| 174 | + })) |
| 175 | + { |
97 | 176 | } |
98 | 177 | } |
99 | 178 | ``` |
100 | 179 |
|
101 | | -An example of the `AutoDomainDataWithSqliteContext` can be found in the [test project](https://github.com/aivascu/EntityFrameworkCore.AutoFixture/tree/master/tests/EntityFrameworkCore.AutoFixture.Tests/Common/Attributes). |
| 180 | +```csharp |
| 181 | +[Theory, PersistenceData] // Notice the data attribute |
| 182 | +public async Task CanUseGeneratedContext(TestDbContext context) |
| 183 | +{ |
| 184 | + // Arrange & Act |
| 185 | + context.Customers.Add(new Customer("Jane Smith")); |
| 186 | + await context.SaveChangesAsync(); |
| 187 | + |
| 188 | + // Assert |
| 189 | + context.Customers.Should().Contain(x => x.Name == "Jane Smith"); |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +For more information about using the `SqliteCustomization` see this [page](./using-sqlite-provider). |
102 | 194 |
|
103 | 195 | ## License |
104 | 196 |
|
|
0 commit comments