Moq.EntityFrameworkCore icon indicating copy to clipboard operation
Moq.EntityFrameworkCore copied to clipboard

Public ConfigureMock or IQueryableExtension

Open esbenbach opened this issue 4 months ago • 0 comments

Hi. Thanks for a very useful library. I have a small feature request:

I have a few cases where I have a DbContext with an IQueryable<TEntity> which points to a DbSet<TEntity>. The IQueryable<TEntity> is typically part of an interface I want to mock, but I want to use EF Core "Async" stuff in the actual implmentation.

Yes I know the implementation will break if ever the IQeuryable is replaced with something that is NOT a DbSet....but thats another story.

When testing I would like to do something like the following:

        var entities = new List<Entity> { existing };
        this.mockContext.Setup(x => x.QueryEntities).ReturnsDbSet(entities);

But that I cannot as ReturnsDbSet is defined on DbSet<T>.

So what I end up doing is to create my own extension method, or in somecases copy/paste the ConfigureMocks method and just call that explictly like so:

   [Fact]
   public void TestStuff()
   {
        var existing = new List<Entity>{ /*here be dragons. */ };
         var entities = new Mock<DbSet<Entity>>(); 
        ConfigureMock(entities , existing);
        this.mockContext.Setup(x => x.QueryEntities).Returns(entities.Object);
   }

    private static void ConfigureMock<TEntity>(Mock dbSetMock, IEnumerable<TEntity> entities) where TEntity : class
    {
        IQueryable<TEntity> entitiesAsQueryable = entities.AsQueryable();
        dbSetMock.As<IAsyncEnumerable<TEntity>>().Setup((IAsyncEnumerable<TEntity> m) => m.GetAsyncEnumerator(CancellationToken.None)).Returns(new InMemoryDbAsyncEnumerator<TEntity>(entitiesAsQueryable.GetEnumerator()));
        dbSetMock.As<IQueryable<TEntity>>().Setup((IQueryable<TEntity> m) => m.Provider).Returns(new InMemoryAsyncQueryProvider<TEntity>(entitiesAsQueryable.Provider));
        dbSetMock.As<IQueryable<TEntity>>().Setup((IQueryable<TEntity> m) => m.Expression).Returns(entitiesAsQueryable.Expression);
        dbSetMock.As<IQueryable<TEntity>>().Setup((IQueryable<TEntity> m) => m.ElementType).Returns(entitiesAsQueryable.ElementType);
        dbSetMock.As<IQueryable<TEntity>>().Setup((IQueryable<TEntity> m) => m.GetEnumerator()).Returns(() => entitiesAsQueryable.GetEnumerator());
    }

It works - but its annoying to repeat all the time.

esbenbach avatar Apr 09 '24 09:04 esbenbach