GithubHelp home page GithubHelp logo

aivascu / entityframeworkcore.autofixture Goto Github PK

View Code? Open in Web Editor NEW
36.0 4.0 5.0 237 KB

A library aimed to minimize the boilerplate required to unit-test Entity Framework Core code using AutoFixture and in-memory providers.

Home Page: https://aivascu.github.io/EntityFrameworkCore.AutoFixture/

License: MIT License

C# 96.10% PowerShell 2.11% Shell 1.64% Batchfile 0.15%
autofixture entity-framework unit-testing unit-test tests database entity-framework-core mocking in-memory sqlite

entityframeworkcore.autofixture's Introduction

EntityFrameworkCore.AutoFixture

GitHub Workflow Status Coveralls github NuGet NuGet downloads GitHub

EntityFrameworkCore.AutoFixture is a library that helps with testing code that uses Entity Framework, by reducing the boilerplate code necessary to set up database contexts (see examples), with the help of AutoFixture.

Unlike other libraries for faking EF contexts, EntityFrameworkCore.AutoFixture does not use mocking frameworks or dynamic proxies in to create database contexts, instead it uses the actual database providers. This ensures the tests will behave a lot more similar to the code in the production environment, with little to no effort.

Supported versions

The current implementation supports all Microsoft.EntityFrameworkCore packages starting from v2.0.0 and AutoFixture starting from v4.4.0, however because the constraints are so low you will have to install the latest versiosn of Microsoft.EntityFrameworkCore and AutoFixture packages yourself, alongside this package.

Make sure to keep in sync the versions of packages used in production and test code. Meaning that if you use Microsoft.EntityFrameworkCore.SqlServer of version v7.0.14, you need to use the equivalent version of Microsoft.EntityFrameworkCore.Sqlite.

Integration Package
SQLite Microsoft.EntityFrameworkCore.Sqlite
In-Memory Microsoft.EntityFrameworkCore.InMemory

⚠️ .NET Standard 2.0 in EF Core v3.0.x ⚠️

Entity Framework Core v3.0.0 - v3.0.3 are targeting netstandard2.1, which means they are not compatible with target frameworks that support at most netstandard2.0 (>= net47 and netcoreapp2.1). Versions after v3.1 are targeting netstandard2.0. If you've encountered this issue consider upgrading to a later version of Entity Framework Core.

⚠️ EF Core v7.0.x ⚠️

If you're using EF Core v7 you must install the corresponding database provider package alongside this library.
So for example if you're using SQLite, you must install Microsoft.EntityFrameworkCore.Sqlite v7.0.0 or later, otherwise your tests will not pass.

Features

EntityFrameworkCore.AutoFixture offers three customizations to help your unit testing workflow:

  • InMemoryCustomization - Customizes fixtures to create contexts using the In-Memory database provider
  • SqliteCustomization - Customizes fixtures to create contexts using the SQLite database provider
  • 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.

Examples

The examples below demonstrate, the possible ways of using the library in xUnit test projects, both with [Fact] and [Theory] tests.

The library is not limited to xUnit and can be used with other testing frameworks like NUnit and MSTest, since it only provides the customizations.

Using In-Memory database provider

By default this customization will configure all contexts to use the in-memory database provider for Enity Framework, and will create the database, giving you a ready to use context.

[Fact]
public async Task CanSavesCustomers()
{
    // Arrange
    var fixture = new Fixture().Customize(new InMemoryCustomization());
    var context = fixture.Create<TestDbContext>();

    // Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

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.

This behavior can be changed by setting the corresponding values in the customizaiton initializer.

[Fact]
public async Task CanSavesCustomers()
{
    // Arrange
    var fixture = new Fixture().Customize(new InMemoryCustomization
    {
        DatabaseName = "MyCoolDatabase", // Sets the store name to "MyCoolDatabase"
        UseUniqueNames = false, // No suffix for store names. All contexts will connect to same store
        OnCreate = OnCreateAction.Migrate // Will run Database.Migrate()
                                          // Use OnCreateAction.None to skip creating the database
    });
    var context = fixture.Create<TestDbContext>();

    // Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

To encapsulate the configuration and remove even more of the boilerplate, use the AutoData attributes offered by AutoFixture.

public class PersistenceDataAttribute : AutoDataAttribute
{
    public PersistenceDataAttribute()
        : base(() => new Fixture().Customize(new InMemoryCustomization {
            UseUniqueNames = false,
            OnCreate = OnCreateAction.Migrate
        }))
    {
    }
}
[Theory, PersistenceData] // Notice the data attribute
public async Task CanUseGeneratedContext(TestDbContext context)
{
    // Arrange & Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

Using SQLite database provider

By default this customization will configure all contexts to use the SQLite database provider for Enity Framework, and will automatically create the database, giving you a ready to use context.

[Fact]
public async Task CanUseGeneratedContext()
{
    // Arrange
    var fixture = new Fixture().Customize(new SqliteCustomization());
    var context = fixture.Create<TestDbContext>();

    // Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

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.

This behavior can be changed by setting the corresponding values in the customizaiton initializer.

[Fact]
public async Task CanSavesCustomers()
{
    // Arrange
    var fixture = new Fixture().Customize(new SqliteCustomization
    {
        ConnectionString = "Data Source=MyDatabase.sqlite;Cache=Shared;", // Sets the connection string to connect to a file
        AutoOpenConnection = false, // Disables opening the connection by default. Affects all SqliteConnection instances.
        OnCreate = OnCreateAction.None // Use OnCreateAction.None to skip creating the database.
                                       // Use OnCreateAction.EnsureCreated to run Database.EnsureCreated() automatically
                                       // Use OnCreateAction.Migrate to run Database.Migrate() automatically
    });
    var connection = fixture.Freeze<SqliteConnection>();
    var context = fixture.Create<TestDbContext>();
    connection.Open();
    context.Database.Migrate();

    // Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

To encapsulate the configuration and remove even more of the boilerplate, use the AutoData attributes offered by AutoFixture.

public class PersistenceDataAttribute : AutoDataAttribute
{
    public PersistenceDataAttribute()
        : base(() => new Fixture().Customize(new SqliteCustomization {
            ConnectionString = "Data Source=MyDatabase;Mode=Memory;Cache=Shared;"
            OnCreate = OnCreateAction.Migrate
        }))
    {
    }
}
[Theory, PersistenceData] // Notice the data attribute
public async Task CanUseGeneratedContext(TestDbContext context)
{
    // Arrange & Act
    context.Customers.Add(new Customer("Jane Smith"));
    await context.SaveChangesAsync();

    // Assert
    context.Customers.Should().Contain(x => x.Name == "Jane Smith");
}

License

Copyright © 2019 Andrei Ivascu.
This project is MIT licensed.

entityframeworkcore.autofixture's People

Contributors

aivascu avatar dependabot-preview[bot] avatar lgtm-com[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

entityframeworkcore.autofixture's Issues

IgnoreQueryFilters Method Not Supported

I am using Global Query Filters in EF Core 6. When I have a query that uses the IgnoreQueryFilters extension method, the test breaks with an exception:

System.NotSupportedException
Specified method is not supported.
   at Microsoft.EntityFrameworkCore.DbSet`1.System.Linq.IQueryable.get_Provider()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.IgnoreQueryFilters[TEntity](IQueryable`1 source)

Is that something that could be fixed in your library or should I try and add my own workaround for it?

Configire InMemoryOptionBuilder

Hi @aivascu,
How possible is it to suppress database transaction warning using this library.
I'm trying to configure DbContextOptions like below.

ConfigureWarnings(x => x.Ignore(InMemoryEventId.TransactionIgnoredWarning)

I can't see any property to achieve this on the InMemoryContextCustomization

Could you help with this please?

Library does not work when used with EF Core 3

When used in combination with EF Core 3 the following exception is being thrown

Message: 
    System.TypeLoadException : Method 'get_Info' in type 'Microsoft.EntityFrameworkCore.Infrastructure.Internal.InMemoryOptionsExtension' from assembly 'Microsoft.EntityFrameworkCore.InMemory, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.
  Stack Trace: 
    InMemoryDbContextOptionsExtensions.UseInMemoryDatabase(DbContextOptionsBuilder optionsBuilder, String databaseName, Action`1 inMemoryOptionsAction)
    InMemoryDbContextOptionsExtensions.UseInMemoryDatabase[TContext](DbContextOptionsBuilder`1 optionsBuilder, String databaseName, Action`1 inMemoryOptionsAction)
    DbContextSpecimenBuilderTests.Create_ShouldBeOfRequestedType_WhenContextResolvesOptions(DbContextSpecimenBuilder builder, Mock`1 contextMock) line 116

No database provider has been configured for this DbContext

Hi, I'm trying to use the package for unit testing services that get a DbContext injected, but I'm getting the following error:

AutoFixture.ObjectCreationExceptionWithPath : AutoFixture was unable to create an instance from AutoFixture.Kernel.SeededRequest because creation unexpectedly failed with exception. Please refer to the inner exception to investigate the root cause of the failure.

with inner exception:

System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.

Used this for setup:

public class InMemoryDataAttribute : AutoDataAttribute
{
    public InMemoryDataAttribute()
        : base(() => new Fixture()
            .Customize(new InMemoryContextCustomization
            {
                OmitDbSets = true,
                AutoCreateDatabase = true
            }))
    {
    }
}

And this is an actual test (not testing anything yet though, but it already gives the error before it enters the test):

[Theory, InMemoryData]
public async Task PlayWithInMemoryData(EmployeeContext employeeContext)
{
    employeeContext.Employees.Add(new Data.Entities.Employee());

    await employeeContext.SaveChangesAsync();
}

I thought the InMemoryContextCustomization was intended for the in-memory database provider. Can you help me out here? Thanks in advance.

Best regards,
Eric Goudriaan

Automate releases

  • Add release drafter to the repository
  • Create a release template
  • Create a release for v0.5

NET 5.0 support

Would it be possible to upgrade the projects so that .NET 5.0 (and later) is supported?

Maybe like @ccpu has done on his fork?
master...ccpu:main

But personally I would still need the support for netstandard2.0 and netstandard 2.1, if possible

Kind regards,
Lazy

Why `EnsureDeleted()`?

Why exactly do we need to call EnsureDeleted?
I can, somewhat understand why we need EnsureCreated, but why exactly do we need to call EnsureDeleted? It seems to work without calling this method.

Would it possible to include these two methods in AutoFixutre somehow?

Publish packages when tagging commit commits

  • Remove the package publishing step from the master workflow
  • Create a new workflow that triggers when a commit is tagged
  • Build project using version from the tag
  • Publish workflow artifacts
  • Publish the package to the NuGet feed
  • Create a GitHub release
  • Compose release changelog from GitHub issues
  • Upload build artifacts to the release

Unable to create DB Context with SQL Server provider

Hi Andrei

Do you have (or could you prepare) any samples showing how to use (or extend) DbContextCustomization to connect to a SQL Server database, for integration test purposes please?

I have created a customization as follows:

public class TestDbContextCustomization : DbContextCustomization
{
    public override void Customize(IFixture fixture)
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile(@"appsettings.json", false, false)
            .AddEnvironmentVariables()
            .Build();

        var connectionString = config["ConnectionStrings:CIServerIntegrationTests"];
        Configure = o => o.UseSqlServer(connectionString);

        OmitDbSets = false;
        OnCreate = OnCreateAction.None;

        base.Customize(fixture);
    }
}

And use the customization as follows:

var fixture = new Fixture().Customize(new TestDbContextCustomization());
var context = fixture.Create<TestDbContext>();
var sale = await context.Sales.FirstOrDefaultAsync();

The db context has a normal constructor:

public TestDbContext(DbContextOptions<TestDbContext> options)
    : base(options)
    {
    }

However it errors with "No database provider has been configured for this DbContext".
Am I missing a step to properly configure the provider?
A breakpoint on the UseSqlServer method call is never hit.

Thank you

Add support for custom DbContext constructors

Implement support for DbContext instance creation using custom constructors.

The custom constructor should contain a DbContextOptions<T> parameter and a number of parameters of other types that will be resolved from the current Fixture.

[Security] Workflow release.yml is using vulnerable action actions/checkout

The workflow release.yml is referencing action actions/checkout using references v1. However this reference is missing the commit a6747255bd19d7a757dbdda8c654a9f84db19839 which may contain fix to the some vulnerability.
The vulnerability fix that is missing by actions version could be related to:
(1) CVE fix
(2) upgrade of vulnerable dependency
(3) fix to secret leak and others.
Please consider to update the reference to the action.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.