Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock EF 6 Async methods using JustMock?

I am trying to Mock Entity Framework 6.0.2 Async methods using JustMock. I am following testing with async queries but it is write using Moq I am trying to convert this into JustMock with help of Mock Multiple Interfaces but getting an exception :

The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

Here is my code :

var dummyData = GetEmployeeSkills();
var mockSet = Mock.Create<DbSet<EmployeeSkill>>();
(mockSet as IDbAsyncEnumerable<EmployeeSkill>).Arrange(x => x.GetAsyncEnumerator())
         .Returns(new TestDbAsyncEnumerator<EmployeeSkill>(dummyData.GetEnumerator()));

(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.Provider).Returns(new TestDbAsyncQueryProvider<EmployeeSkill>(dummyData.Provider));

(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.Expression).Returns(dummyData.Expression);
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.ElementType).Returns(dummyData.ElementType);
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.GetEnumerator()).Returns(dummyData.GetEnumerator());

var mockContext = Mock.Create<TimeSketchContext>();
mockContext.Arrange(x => x.Set<EmployeeSkill>()).Returns(mockSet);

baseRepository = new BaseRepository<EmployeeSkill>(mockContext);

private EmployeeSkill GetEmployeeSkill()
    {
        return new EmployeeSkill
        {
            SkillDescription = "SkillDescription",
            SkillName = "SkillName",
            Id = 1
        };
    }

    private IQueryable<EmployeeSkill> GetEmployeeSkills()
    {
        return new List<EmployeeSkill>
        {
            GetEmployeeSkill(),
            GetEmployeeSkill(),
            GetEmployeeSkill(),
        }.AsQueryable();
    }

Test :

[Fact]
public async Task DbTest()
{
   var data = await baseRepository.FindAsync(1);
   Assert.NotEqual(null, data);
}

Repository :

public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
{
    protected readonly DbContext InnerDbContext;
    protected DbSet<T> InnerDbSet;

    public BaseRepository(IDbContext innerDbContext)
    {
        InnerDbContext = innerDbContext as DbContext;
        InnerDbSet = innerDbContext.Set<T>();
    }

    public virtual Task<T> FindAsync(long id)
    {
        return InnerDbSet.FirstOrDefaultAsync(x=>x.Id == id);
    }
 }

Interface :

public interface IDbContext
{
    DbSet<T> Set<T>() where T : class;
}

Context :

public class TimeSketchContext : DbContext, IDbContext
{
    public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}
like image 609
Hasanuzzaman Avatar asked Nov 01 '22 07:11

Hasanuzzaman


1 Answers

Because JustMock can mock non virtual methods when you are writing

var mockContext = Mock.Create<TimeSketchContext>();
mockContext.Arrange(x => x.Set<EmployeeSkill>()).Returns(mockSet);

it will mock the DbContext.Set<> and not your IDbContext.Set<> so you get the exception.

There are at least 2 solution to this:

  • Mock your IDbContext interface

    var mockContext = Mock.Create<IDbContext>();
    
  • Or change back your BaseRepository to use a DbContext instead of your interface:

    public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
    {
        protected readonly DbContext InnerDbContext;
        protected DbSet<T> InnerDbSet;
    
        public BaseRepository(DbContext innerDbContext)
        {
            InnerDbContext = innerDbContext;
            InnerDbSet = InnerDbContext.Set<T>();
        }
    
        public virtual Task<T> FindAsync(long id)
        {
            return InnerDbSet.FirstOrDefaultAsync(x => x.Id == id);
        }
    }  
    
like image 180
nemesv Avatar answered Nov 14 '22 14:11

nemesv