Tony
Tony

Reputation: 12695

NSubstitute for the EF's Core DbContext - how to use it?

I'm trying to create the unit test for a class which uses my EF Core DbContext:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    public DbSet<SomeTable> SomeTables { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
    }
}

the class which is consuming that context is simple:

public class MyClass
{
    public MyClass(MyContext db)
    {
    }
}

so, when I try to create

var fakeContext = Substitute.For<MyContext>();

which ends with the error:

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: MyContext.
Could not find a parameterless constructor.

which is being raised by base(options) constructor. So, the net approach was to extend the code:

var dbContextOptions = Substitute.For<DbContextOptions<MyContext>>();

dbContextOptions.ContextType.Returns(typeof(MyContext));

var dbContextOptionsExtension = Substitute.For<IEnumerable<IDbContextOptionsExtension>>();
dbContextOptions.Extensions.Returns(dbContextOptionsExtension);

var myFakeContext = Substitute.For<MyContext>(dbContextOptions);

but it generates more and errors. So, how to fix it ?

Upvotes: 6

Views: 7466

Answers (2)

Tony
Tony

Reputation: 12695

Ok, I've used the InMemory provider:

var options = new DbContextOptionsBuilder<AgreementContext>()
                .UseInMemoryDatabase("fakeDb")
                .Options;

var agreementContext = Substitute.For<MyContext>(options);

Upvotes: 2

rgvlee
rgvlee

Reputation: 3193

You haven't elaborated on the additional errors so I can't provide a specific answer, however trying to mock a DbContext properly is difficult. IMO there are two options.

1) Use the Microsoft in-memory provider.

2) If you want to use a mocked DbContext using NSubstitute, use a pre-existing library that does the mocking for you. There are a few around such as EntityFrameworkCore.Testing.NSubstitute (disclaimer - I am the author).

The in-memory provider is not a complete implementation, it can't do relational operations and there are a swag of LINQ operations it doesn't support, so depending on your use cases the latter may be a better solution.

If you have a specific error/use case in mind pop it up and I may be able to provide a better answer.

Upvotes: 8

Related Questions