How to fake DbContextOptions

314 Views Asked by At

I'm writing a unit test for ConsumerService that uses EntityFramework Core. Below you can see my AppDBContext class, and its one and only constructor. In order to fake it, I'm required to pass DbContext into it, so, I'm trying to fake that one too. I'm having an issue faking the DbContext object.

Here is my AppDBContext class:

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

**Consumer **class then wires it in like this:

        private readonly AppDbContext _db;

        public ConsumerService(AppDbContext db)
        {
            _db = db;
        }

I'm trying to write a unit test for the consumer class.

I've tried this:

        private readonly DbContextOptions<AppDbContext> _options;
        private readonly AppDbContext _db;
        private readonly ConsumerService _consumerService ;

        public ConsumerServiceTests()
        {
            //Dependencies
            _options = A.Fake<DbContextOptions<AppDbContext>>();
            _db = A.Fake<AppDbContext>(x => x.WithArgumentsForConstructor(() => new AppDbContext(_options)));

            //SUT
            _consumerService = new ConsumerService(_db);
        }

I'm getting this error:

Message:  FakeItEasy.Core.FakeCreationException : Failed to create fake of type API.Data.AppDbContext: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the AppDbContextProxy constructor must be a DbContextOptions. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at API.Data.AppDbContext..ctor(DbContextOptions1 options) in C:\Users\...\API\Data\AppDbContext.cs:line 8 at Castle.Proxies.AppDbContextProxy..ctor(IInterceptor[], DbContextOptions1 options) at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

NOTE

  1. I use FakeItEasy.
  2. No, I don't want to use InMemoryDatabase. I need to fake DbContext.
2

There are 2 best solutions below

0
RezaNoei On

I'm usually use InMemoryDatabase for testing my services. By the way you should Instantiate a DbContextOptionsBuilder:

 var options = new DbContextOptionsBuilder<Context>().Options;

It gives you what you wanted.

0
Elyas Esna On

You can create an abstract class and then use it in other classes by inheriting it, like:

public abstract class BaseDbContext
{
  protected AppDbContext _db;
  
  public BaseDbContext()
  {
    var builder = new DbContextOptionsBuilder<AppDbContext>();
    builder.UseSqlite("DataSource:=memory:", _ => {});
    _db = new AppDbContext(builder.Options);
    _db.Database.OpenConnection();
    _db.Database.EnsureCreated();
  }
}