Skip to content

Commit 730813f

Browse files
authored
Updated the documentation website (#115)
1 parent 0f08612 commit 730813f

File tree

3 files changed

+350
-57
lines changed

3 files changed

+350
-57
lines changed

docs/index.md

Lines changed: 140 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,99 +6,191 @@
66
[![Nuget](https://img.shields.io/nuget/v/EntityFrameworkCore.AutoFixture?logo=nuget&style=flat-square)](https://www.nuget.org/packages/EntityFrameworkCore.AutoFixture/)
77
[![GitHub](https://img.shields.io/github/license/aivascu/EntityFrameworkCore.AutoFixture?logo=MIT&style=flat-square)](https://licenses.nuget.org/MIT)
88

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).
1010

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.
1213

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:
1415

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.
1620

1721
## Features
1822

19-
**EntityFrameworkCore.AutoFixture** offers three customizations to aid your unit testing workflow:
23+
**EntityFrameworkCore.AutoFixture** offers three customizations to help your unit testing workflow:
2024

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.
2528

2629
## Examples
2730

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.
2932

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.
3134

3235
### Using In-Memory database provider
3336

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+
3439
```csharp
3540
[Fact]
36-
public void SaveChanges_ShouldCreateCustomerRecord()
41+
public async Task CanSavesCustomers()
3742
{
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>();
4246

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();
4550

46-
context.Customers.Should().Contain(x => x.Name == "John Doe");
47-
}
51+
// Assert
52+
context.Customers.Should().Contain(x => x.Name == "Jane Smith");
4853
}
4954
```
5055

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.
5259

5360
```csharp
54-
[Theory]
55-
[AutoDomainDataWithInMemoryContext]
56-
public async Task SaveChangesAsync_ShouldCreateCustomerRecord(TestDbContext context)
61+
[Fact]
62+
public async Task CanSavesCustomers()
5763
{
58-
await using (context)
64+
// Arrange
65+
var fixture = new Fixture().Customize(new InMemoryCustomization
5966
{
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+
```
6182

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.
6484

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+
{
6694
}
6795
}
6896
```
6997

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).
71112

72113
### Using SQLite database provider
73114

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.
76116

77117
```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()
82120
{
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>();
89124

90-
context.Customers.Add(customer);
91-
context.SaveChanges();
125+
// Act
126+
context.Customers.Add(new Customer("Jane Smith"));
127+
await context.SaveChangesAsync();
92128

93-
customer.Order(item, 5);
94-
context.SaveChanges();
129+
// Assert
130+
context.Customers.Should().Contain(x => x.Name == "Jane Smith");
131+
}
132+
```
95133

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+
{
97176
}
98177
}
99178
```
100179

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).
102194

103195
## License
104196

docs/using-in-memory-provider.md

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,90 @@
11
# Using the In-Memory provider
22

3+
Below is the most basic usage of the library using the In-Memory provider for EF Core.
4+
5+
```csharp
6+
[Fact]
7+
public void CanAddCustomers()
8+
{
9+
var fixture = new Fixture().Customize(new InMemoryCustomization());
10+
var context = fixture.Create<TestDbContext>();
11+
12+
context.Customers.Add(new Customer("John Doe"));
13+
context.SaveChanges();
14+
15+
context.Customers.Should().Contain(x => x.Name == "John Doe");
16+
}
17+
```
18+
19+
This test is equivalent to the following test written using the EF Core API.
20+
21+
```csharp
22+
[Fact]
23+
public async Task CanAddCustomers()
24+
{
25+
// Arrange
26+
var builder = new DbContextOptionsBuilder<TestDbContext>()
27+
.UseInMemory("TestDatabase");
28+
var options = builder.Options;
29+
var context = new TestDbContext(options);
30+
context.Database.EnsureCreated();
31+
32+
// Act
33+
context.Customers.Add(new Customer("Jane Smith"));
34+
await context.SaveChangesAsync();
35+
36+
// Assert
37+
context.Customers.Should().Contain(x => x.Name == "Jane Smith");
38+
}
39+
```
40+
41+
## Cheat sheet
42+
43+
### Using custom database names
44+
45+
In some scenarios it might be required to use a different database (store) name than the default `TestDatabase`.
46+
To change the database name used by the customization, simply set the `DatabaseName` property to the required value.
47+
The database name set in the customization, will be used by all database contexts created by AutoFixture.
48+
49+
```csharp
50+
[Fact]
51+
public async Task CanAddCustomers()
52+
{
53+
// Arrange
54+
var fixture = new Fixture().Customize(new InMemoryCustomization {
55+
DatabaseName = "MyDatabase",
56+
UseUniqueNames = false,
57+
});
58+
var context = fixture.Create<TestDbContext>();
59+
60+
// Act
61+
context.Customers.Add(new Customer("Jane Smith"));
62+
await context.SaveChangesAsync();
63+
64+
// Assert
65+
context.Customers.Should().Contain(x => x.Name == "Jane Smith");
66+
}
67+
```
68+
69+
### Multiple connections to same instance
70+
71+
In order to create multiple contexts that all connect to the same instance, ensure that the `UseUniqueNames` property is set to `false`. This will remove the unique suffix generated by default for database names.
72+
373
```csharp
474
[Fact]
5-
public void SaveChanges_ShouldCreateCustomerRecord()
75+
public async Task CanAddCustomers()
676
{
7-
var fixture = new Fixture().Customize(new InMemoryContextCustomization());
8-
using (var context = fixture.Create<TestDbContext>())
9-
{
10-
context.Database.EnsureCreated();
77+
// Arrange
78+
var fixture = new Fixture().Customize(new InMemoryCustomization { UseUniqueNames = false });
79+
var context1 = fixture.Create<TestDbContext>();
80+
var customer = fixture.Create<Customer>();
81+
context1.Customers.Add(customer);
82+
await context1.SaveChangesAsync();
1183

12-
context.Customers.Add(new Customer("John Doe"));
13-
context.SaveChanges();
84+
// Act
85+
var context2 = fixture.Create<TestDbContext>(); // Note that we're crating a new context
1486
15-
context.Customers.Should().Contain(x => x.Name == "John Doe");
16-
}
87+
// Assert
88+
context2.Customers.Include(x => x.Orders).Should().BeEquivalentTo(customer);
1789
}
1890
```

0 commit comments

Comments
 (0)