我是嘲笑的新手.我想模拟我的基础存储库,它依赖于Entity Framework 6 DbContext但是我失败了.我在Google搜索了很多但没有得到任何足够的结果.最后我得到了一个使用异步查询进行测试的示例,并尝试关注但它对我有用.
这是我的代码:
DbContext:
public class TimeSketchContext : DbContext { public virtual DbSetEmployeeSkill { get; set; } }
基础知识库:
public class BaseRepository: IRepositoryBase where T : class, IEntity, new() { protected readonly DbContext InnerDbContext; protected DbSet InnerDbSet; public BaseRepository(DbContext innerDbContext) { InnerDbContext = innerDbContext; InnerDbSet = InnerDbContext.Set (); } public virtual Task FindAsync(long id) { return InnerDbSet.FirstOrDefaultAsync(x=>x.Id == id); }
}
测试:
[Fact] public async Task DbTest() { var dummyData = GetEmployeeSkills(); var mockSet = new Mock>(); mockSet.As >() .Setup(x => x.GetAsyncEnumerator()) .Returns(new TestDbAsyncEnumerator (dummyData.GetEnumerator())); mockSet.As >() .Setup(x => x.Provider) .Returns(new TestDbAsyncQueryProvider (dummyData.Provider)); mockSet.As >().Setup(m => m.Expression).Returns(dummyData.Expression); mockSet.As >().Setup(m => m.ElementType).Returns(dummyData.ElementType); mockSet.As >().Setup(m => m.GetEnumerator()).Returns(dummyData.GetEnumerator()); var mockContext = new Mock (); mockContext.Setup(c => c.EmployeeSkill).Returns(mockSet.Object); var baseRepository = new BaseRepository (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 GetEmployeeSkills() { return new List { GetEmployeeSkill(), GetEmployeeSkill(), GetEmployeeSkill(), }.AsQueryable(); }
结果是:
Assert.NotEqual()失败
我认为问题是
public BaseRepository(DbContext innerDbContext) { InnerDbContext = innerDbContext; InnerDbSet = InnerDbContext.Set(); <<<<<<<<<<< }
但不明白为什么以及如何解决这个问题.
我在用 :
Visual Studio 2013 Ultimate
起订量
的xUnit
提前谢谢.
你是对的,问题出在你的InnerDbContext.Set<T>();
陈述中.
在EF(6.0.2)的当前版本的DbContext.Set<T>
方法是不 virtual
因此它不能与起订量被嘲笑.
所以你不能轻易地让你的测试通过,除非通过改变你的设计而BaseRepository
不是依赖于整体,DbContext
而是在一个DbSet<T>
:
所以类似于:
public BaseRepository(DbSet<T> dbSet) { InnerDbSet = dbSet; }
然后你可以直接在你的模拟DbSet中传递.
或者您可以为以下内容创建包装器界面DbContext
:
public interface IDbContext { DbSet<T> Set<T>() where T : class; } public class TimeSketchContext : DbContext, IDbContext { public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; } }
然后使用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); } }
最后,您只需要在测试中更改两行以使其通过:
var mockContext = new Mock<IDbContext>(); mockContext.Setup(c => c.Set<EmployeeSkill>()).Returns(mockSet.Object);