Hello. I try to unit test my services and by that I need to provide Mapper instance to the constructor (I'm using DI). I've read in SO comments from Jimmy, that mocking Mapper is not a good idea. So I ended up constructing real Mapper instance and provide it to the consumer.
public class UserProfile : Profile
{
public AccountProfile()
{
this.CreateMap<ApplicationUser, UserDto>();
}
}
AutoMapper.Extensions.Microsoft.DependencyInjection Version="6.1.1"
Npgsql.EntityFrameworkCore.PostgreSQL Version="2.1.2"
I get the following error:
System.InvalidOperationException : The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
I'm manually constructing Mapper instance in order to provide it to the service. This is setup in my test:
var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(Assembly.Load("api")));
var mapper = new Mapper(configuration);
And construct my service:
var service = new UserService(
dbContextMock.Object,
identityOptionsMock.Object,
jwtOptionsMock.Object,
mapper);
In my service I'm calling:
public async Task<UserDto> GetUserAccountAsync(string id)
{
return await dbContext
.ApplicationUsers
.Where(v => v.Id == id)
.ProjectTo<UserDto>(mapper.ConfigurationProvider)
.SingleOrDefaultAsync();
}
The strangest thing about this is, that my production code is working as expected.
I had the same issue with v5.0.1 and then upgraded to 6.1.1 with hope to resolve that.
Also important, that tried with synchronous call and that succeeded. Probably ProjectTo doesn't really implement IAsyncQueryProvider.
Would you also suggest the best way to use AutoMapper when unit testing?
What if I want to mock Mapper instance in order to test how the system behaves if mapping fails?
Thanks!
Don't mock AutoMapper. Just use the real thing. I've never mocked
AutoMapper in the 10 years I've used it.
On Sat, Jul 27, 2019 at 3:29 AM Georgi Marokov notifications@github.com
wrote:
Hello. I try to unit test my services and by that I need to provide Mapper
instance to the constructor (I'm using DI). I've read in SO comments from
Jimmy, that mocking Mapper is not a good idea. So I ended up constructing
real Mapper instance and provide it to the consumer.
Mapping configurationpublic class UserProfile : Profile
{
public AccountProfile()
{
this.CreateMap();
}
}Version:
AutoMapper.Extensions.Microsoft.DependencyInjection Version="6.1.1"
Npgsql.EntityFrameworkCore.PostgreSQL Version="2.1.2"
Actual behaviorI get the following error:
System.InvalidOperationException : The provider for the source IQueryable
doesn't implement IAsyncQueryProvider. Only providers that implement
IEntityQueryProvider can be used for Entity Framework asynchronous
operations.
Steps to reproduceI'm manually constructing Mapper instance in order to provide it to the
service. This is setup in my test:var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(Assembly.Load("api")));
var mapper = new Mapper(configuration);And construct my service:
var service = new UserService(
dbContextMock.Object,
identityOptionsMock.Object,
jwtOptionsMock.Object,
mapper
);In my service I'm calling:
public async Task
GetUserAccountAsync(string id)
{
return await dbContext
.ApplicationUsers
.Where(v => v.Id == id)
.ProjectTo(mapper.ConfigurationProvider)
.SingleOrDefaultAsync();
}The strangest thing about this is, that my production code is working as
expected.
I had the same issue with v5.0.1 and then upgraded to 6.1.1 with hope to
resolve that.
Also important, that tried with synchronous call and that succeeded.
Probably ProjectTo doesn't really implement IAsyncQueryProvider.Would you also suggest the best way to use AutoMapper when unit testing?
What if I want to mock Mapper instance in order to test how the system
behaves if mapping fails?Thanks!
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/3175?email_source=notifications&email_token=AAAZQMWNTYIVL4BIT3KLXLLQBQBN5A5CNFSM4IHIYJH2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HB2ZQNA,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAZQMTPIEUXIB5UY5BFH5DQBQBN5ANCNFSM4IHIYJHQ
.
Great but that doesn't seems to solve my issue with IAsyncQueryProvider not being implemented. Is this a miss configuration of my Mapper instance (which I create manually not being injected from DI) or a real issue?
Yeah, you're trying to mock DbContext - that's also very
difficult/impossible to do.
If you want unit tests with DbContext - use the in-memory provider for it
instead.
On Mon, Jul 29, 2019 at 9:30 AM Georgi Marokov notifications@github.com
wrote:
Great but that doesn't seems to solve my issue with IAsyncQueryProvider
not being implemented. Is this a miss configuration of my Mapper instance
(which I create manually not being injected from DI) or a real issue?—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/3175?email_source=notifications&email_token=AAAZQMWYYE23G2HH26DALNTQB35G7A5CNFSM4IHIYJH2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3A4OKA#issuecomment-516015912,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAZQMS2HO6ETES5W4PNA43QB35G7ANCNFSM4IHIYJHQ
.
Here is my DbContext mock which works just fine:
private void CreateDbContext()
{
var persons = GetFakeData().AsQueryable();
var dbSet = new Mock<DbSet<ApplicationUser>>();
dbSet.As<IQueryable<ApplicationUser>>().Setup(m => m.Provider).Returns(persons.Provider);
dbSet.As<IQueryable<ApplicationUser>>().Setup(m => m.Expression).Returns(persons.Expression);
dbSet.As<IQueryable<ApplicationUser>>().Setup(m => m.ElementType).Returns(persons.ElementType);
dbSet.As<IQueryable<ApplicationUser>>().Setup(m => m.GetEnumerator()).Returns(persons.GetEnumerator());
this.dbContextMock = new Mock<DefaultDbContext>();
this.dbContextMock.Setup(c => c.ApplicationUsers).Returns(dbSet.Object);
}
private IEnumerable<ApplicationUser> GetFakeData()
{
var users = A.ListOf<ApplicationUser>(26);
users.ForEach(x => x.Id = new Guid().ToString());
return users.Select(_ => _);
}
I avoid using the InMemoryDatabase as the test becomes more like integration.
From your answer I assume Mapper depends on DbContext, specifically ProjectTo
Given the code to test, the right approach to testing it is the one @jbogard is suggesting. But if for some reason you'd rather not write that kind of tests, then you should rewrite the code to test. It should not depend on DbContext and ProjectTo, but on some abstractions that are more amenable to mocking. So I think there is a mismatch here between the approach to writing the code and the tests. I guess it's a question of priorities.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Don't mock AutoMapper. Just use the real thing. I've never mocked
AutoMapper in the 10 years I've used it.
On Sat, Jul 27, 2019 at 3:29 AM Georgi Marokov notifications@github.com
wrote: