[英]How to mock Entity Framework 6 Async methods?
I am new in mocking. 我是嘲笑的新手。 I want to mock up my base repository which is depend on Entity Framework 6 DbContext But I fail. 我想模拟我的基础存储库,它依赖于Entity Framework 6 DbContext但是我失败了。 I searched in Google a lot but did not get any sufficient result. 我在Google搜索了很多但没有得到任何足够的结果。 At last I got an example at testing with async queries and try to follow but it is worked for me. 最后我得到了一个使用异步查询进行测试的示例,并尝试关注但它对我有用。
Here is my code : 这是我的代码:
DbContext : DbContext:
public class TimeSketchContext : DbContext
{
public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}
Base Repository : 基础知识库:
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);
}
} }
Test : 测试:
[Fact]
public async Task DbTest()
{
var dummyData = GetEmployeeSkills();
var mockSet = new Mock<DbSet<EmployeeSkill>>();
mockSet.As<IDbAsyncEnumerable<EmployeeSkill>>()
.Setup(x => x.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<EmployeeSkill>(dummyData.GetEnumerator()));
mockSet.As<IQueryable<EmployeeSkill>>()
.Setup(x => x.Provider)
.Returns(new TestDbAsyncQueryProvider<EmployeeSkill>(dummyData.Provider));
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.Expression).Returns(dummyData.Expression);
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.ElementType).Returns(dummyData.ElementType);
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.GetEnumerator()).Returns(dummyData.GetEnumerator());
var mockContext = new Mock<TimeSketchContext>();
mockContext.Setup(c => c.EmployeeSkill).Returns(mockSet.Object);
var baseRepository = new BaseRepository<EmployeeSkill>(mockContext.Object);
var data = await baseRepository.FindAsync(1);
Assert.NotEqual(null, data);
}
private EmployeeSkill GetEmployeeSkill()
{
return new EmployeeSkill
{
SkillDescription = "SkillDescription",
SkillName = "SkillName",
Id = 1
};
}
private IQueryable<EmployeeSkill> GetEmployeeSkills()
{
return new List<EmployeeSkill>
{
GetEmployeeSkill(),
GetEmployeeSkill(),
GetEmployeeSkill(),
}.AsQueryable();
}
Result is : 结果是:
Assert.NotEqual() Failure Assert.NotEqual()失败
I think problem is 我认为问题是
public BaseRepository(DbContext innerDbContext)
{
InnerDbContext = innerDbContext;
InnerDbSet = InnerDbContext.Set<T>(); <<<<<<<<<<<
}
But don`t understand why and how to solve this. 但不明白为什么以及如何解决这个问题。
I am using : 我在用 :
Thank`s in advance. 提前谢谢。
You are right the problem is in your InnerDbContext.Set<T>();
你说得对,问题出在你的InnerDbContext.Set<T>();
statement. 声明。
In the current version of the EF (6.0.2) the DbContext.Set<T>
method is not virtual
so it cannot be mocked with Moq. 在当前版本的EF(6.0.2)中, DbContext.Set<T>
方法 不是 virtual
因此无法使用Moq进行virtual
。
So you cannot easily make your test pass except by changing your design of the BaseRepository
to not depend on the whole DbContext
but on one DbSet<T>
: 因此,除非将BaseRepository
的设计更改为不依赖于整个DbContext
而是依赖于一个DbSet<T>
否则您无法轻松进行测试通过:
So something like: 所以类似于:
public BaseRepository(DbSet<T> dbSet)
{
InnerDbSet = dbSet;
}
Then you can pass directly in your mocked DbSet. 然后你可以直接在你的模拟DbSet中传递。
Or you can create a wrapper interface for DbContext
: 或者您可以为DbContext
创建一个包装器接口:
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
}
public class TimeSketchContext : DbContext, IDbContext
{
public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}
Then use IDbContext
in your BaseRepository
: 然后使用IDbContext
在BaseRepository
:
public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
{
protected readonly IDbContext InnerDbContext;
protected DbSet<T> InnerDbSet;
public BaseRepository(IDbContext innerDbContext)
{
InnerDbContext = innerDbContext;
InnerDbSet = InnerDbContext.Set<T>();
}
public virtual Task<T> FindAsync(long id)
{
return InnerDbSet.FirstOrDefaultAsync(x => x.Id == id);
}
}
And finally you just need to change two lines in your test to make it pass: 最后,您只需要在测试中更改两行以使其通过:
var mockContext = new Mock<IDbContext>();
mockContext.Setup(c => c.Set<EmployeeSkill>()).Returns(mockSet.Object);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.