英文:
Mocking IQueryable object in TenantDbContext
问题
这里是我的DbContext
方法:
public class TenantDbContext : IdentityDbContext<AspNetUser, AspNetRole, Guid,
AspNetUserClaim, AspNetUserRole,
AspNetUserLogin, AspNetRoleClaim,
AspNetUserToken>
{
private readonly IConfiguration _configuration;
private readonly IHttpContextData _contextData;
private readonly IDbUtilities _dbUtilities;
private readonly IMemoryCache _memoryCache;
private readonly SeedStatikReferanslar _seedStatikReferanslar;
private readonly SeedRefTip _seedSystemReferanslar;
private readonly SeedSysParams _seedSysParams;
private readonly SeedReferanslar _seedReferanslar;
public TenantDbContext(DbContextOptions<TenantDbContext> options,
IMemoryCache memoryCache,
IHttpContextData contextData,
SeedStatikReferanslar seedStatikReferanslar,
IConfiguration configuration,
IDbUtilities dbUtilities,
SeedRefTip seedSystemReferanslar,
SeedSysParams seedSysParams,
SeedReferanslar seedReferanslar,
bool DoNotSeedDB = false) : base(options)
{
_memoryCache = memoryCache;
_contextData = contextData;
_seedStatikReferanslar = seedStatikReferanslar;
_configuration = configuration;
_dbUtilities = dbUtilities;
_seedSystemReferanslar = seedSystemReferanslar;
_seedSysParams = seedSysParams;
_seedReferanslar = seedReferanslar;
DoNotSeed = DoNotSeedDB;
}
public virtual DbSet<Stok> Stok { get; set; } //(以及更多的DbSet)
}
这是我的存储库示例:
public class StokRepository : AsyncRepository<Stok>, IStokRepository
{
private readonly TenantDbContext _tenantDbContext;
public StokRepository(TenantDbContext dbContext) : base(dbContext)
{
_tenantDbContext = dbContext;
}
public async Task<Stok> GetByIdAsync(Guid Id, bool withRelationalTables = false, bool withReferences = false)
{
var query = _tenantDbContext.Stok.Where(x => x.Id == Id);//我想设置这个查询
if (withRelationalTables)
{
query = query
.Include(x => x.StokNotlar)
.Include(x => x.StokTeminler).ThenInclude(x => x.CariHesap)
.Include(x => x.StokFiyat)
.Include(x => x.StokMuhasebe)
.Include(x => x.StokBirimler).ThenInclude(x => x.BirimBarkods)
.Include(x => x.GTIP);
}
Stok stok = await query.FirstOrDefaultAsync();
if (stok == null)
return null;
if (withReferences)
await MatchStokWithReferans(new List<Stok> { stok });
stok = (await GetAllStokWithSanalSahalarAsync(new List<Stok> { stok })).FirstOrDefault();
return stok;
}
}
我想设置:
var query = _tenantDbContext.Stok.Where(x => x.Id == Id);
我的测试方法:
[Fact]
public async void StokRepoTest()
{
IQueryable<Stok> data = new List<Stok>()
{
new Stok()
{
Id = Guid.NewGuid(),
MalKodu = "abc"
}}.AsQueryable();
var mockSet = new Mock<DbSet<Stok>>();
mockSet.As<IQueryable<Stok>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Stok>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Stok>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Stok>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var contextMock = new Mock<TenantDbContext>
(
new DbContextOptions<TenantDbContext>(),
null,
null,
null,
null,
null,
null,
null,
null,
false);
contextMock.Setup(x => x.Stok)
.Returns(mockSet.Object);
StokRepository stokRepository = new StokRepository(contextMock.Object);
var stok = await stokRepository.GetByIdAsync(Guid.NewGuid(), false, false);
Assert.NotNull(stok);
}
在执行时返回的错误消息:
The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations
英文:
Here is my DbContext
methods:
public class TenantDbContext : IdentityDbContext<AspNetUser, AspNetRole, Guid,
AspNetUserClaim, AspNetUserRole,
AspNetUserLogin, AspNetRoleClaim,
AspNetUserToken>
{
private readonly IConfiguration _configuration;
private readonly IHttpContextData _contextData;
private readonly IDbUtilities _dbUtilities;
private readonly IMemoryCache _memoryCache;
private readonly SeedStatikReferanslar _seedStatikReferanslar;
private readonly SeedRefTip _seedSystemReferanslar;
private readonly SeedSysParams _seedSysParams;
private readonly SeedReferanslar _seedReferanslar;
public TenantDbContext(DbContextOptions<TenantDbContext> options,
IMemoryCache memoryCache,
IHttpContextData contextData,
SeedStatikReferanslar seedStatikReferanslar,
IConfiguration configuration,
IDbUtilities dbUtilities,
SeedRefTip seedSystemReferanslar,
SeedSysParams seedSysParams,
SeedReferanslar seedReferanslar,
bool DoNotSeedDB = false) : base(options)
{
_memoryCache = memoryCache;
_contextData = contextData;
_seedStatikReferanslar = seedStatikReferanslar;
_configuration = configuration;
_dbUtilities = dbUtilities;
_seedSystemReferanslar = seedSystemReferanslar;
_seedSysParams = seedSysParams;
_seedReferanslar = seedReferanslar;
DoNotSeed = DoNotSeedDB;
}
{
public virtual DbSet<Stok> Stok { get; set; } //(and more DbSet)
}
}
Here are my Repository samples:
public class StokRepository : AsyncRepository<Stok>, IStokRepository
{
private readonly TenantDbContext _tenantDbContext;
public StokRepository(TenantDbContext dbContext) : base(dbContext)
{
_tenantDbContext = dbContext;
}
public async Task<Stok> GetByIdAsync(Guid Id, bool withRelationalTables = false, bool withReferences = false)
{
var query = _tenantDbContext.Stok.Where(x => x.Id == Id);//I want setup this
if (withRelationalTables)
{
query = query
.Include(x => x.StokNotlar)
.Include(x => x.StokTeminler).ThenInclude(x => x.CariHesap)
.Include(x => x.StokFiyat)
.Include(x => x.StokMuhasebe)
.Include(x => x.StokBirimler).ThenInclude(x => x.BirimBarkods)
.Include(x => x.GTIP);
}
Stok stok = await query.FirstOrDefaultAsync();
if (stok == null)
return null;
if (withReferences)
await MatchStokWithReferans(new List<Stok> { stok });
stok = (await GetAllStokWithSanalSahalarAsync(new List<Stok> { stok })).FirstOrDefault();
return stok;
}
i want to setup :
var query = _tenantDbContext.Stok.Where(x => x.Id == Id);
my test method:
[Fact]
public async void StokRepoTest()
{
IQueryable<Stok> data = new List<Stok>()
{
new Stok()
{
Id = Guid.NewGuid(),
MalKodu = "abc"
}}.AsQueryable();
var mockSet = new Mock<DbSet<Stok>>();
mockSet.As<IQueryable<Stok>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Stok>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Stok>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Stok>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var contextMock = new Mock<TenantDbContext>
(
new DbContextOptions<TenantDbContext>(),
null,
null,
null,
null,
null,
null,
null,
null,
false);
contextMock.Setup(x => x.Stok)
.Returns(mockSet.Object);
StokRepository stokRepository = new StokRepository(contextMock.Object);
var stok = await stokRepository.GetByIdAsync(Guid.NewGuid(), false, false);
Assert.NotNull(stok);
}
The error message that is returned while :
The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations
答案1
得分: 1
In order to override members of your class, you need to use the virtual
keyword. So try to change to:
public virtual DbSet<Stok> Stok { get; set; }
英文:
In order to override members of your class, you need to use the virtual
keyword. So try to change to:
public virtual DbSet<Stok> Stok { get; set; }
答案2
得分: 1
Instead of trying to mock the context, use an in-memory database:
var options = new DbContextOptionsBuilder().UseInMemoryDatabase("YourInMemoryDbName").Options;
You can then use this options
object to create your context instance.
Populate your in-memory database with your sample records prior to running the test.
You can read more about it here.
It should be pointed out that this kind of testing is discouraged, mainly because of the differences between the implementations of the In-Memory database and a real MS SQL instance.
You already have a repository abstraction on top of the context so mocking the repos should suffice for your testing purposes. If you find yourself needing to unit test your repos, then it's time to take a step back and review your code as repos should be pretty dumb and only implement logic needed to access the data store.
英文:
Instead of trying to mock the context, use an in-memory database:
var options = new DbContextOptionsBuilder().UseInMemoryDatabase("YourInMemoryDbName").Options;
You can then use this options
object to create your context instance.
Populate your in-memory database with your sample records prior to running the test.
You can read more about it here.
It should be pointed out that this kind of testing is discouraged, mainly because of the differences between the implementations of the In-Memory database and a real MS SQL instance.
You already have a repository abstraction on top of the context so mocking the repos should suffice for your testing purposes. If you find yourself needing to unit test your repos, then it's time to take a step back and review your code as repos should be pretty dumb and only implement logic needed to access the data store.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论