Reputation: 12695
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
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
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