我正在开发一个Asp.Net mvc应用程序。我正在对我的应用程序进行单元测试。我使用Moq来模拟对象。在我的测试中,我需要模拟数据库上下文及其DbSet。我可以模拟数据库上下文和测试。但问题是我必须在上下文类中将DbSet<Entity>
实体更改为IDbSet<Entity>
实体。
这是我如何模拟上下文类
的示例[TestMethod]
public void GenerateItemCode_IncreaseDigit()
{
var data = new List<Item>{
new Item{
Id = 2,
ItemCode = "CD345678"
}
}.AsQueryable();
var dbSetMock = new Mock<IDbSet<Item>>();
dbSetMock.Setup(m => m.Provider).Returns(data.Provider);
dbSetMock.Setup(m => m.Expression).Returns(data.Expression);
dbSetMock.Setup(m => m.ElementType).Returns(data.ElementType);
dbSetMock.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var storeContext = new Mock<StoreContext>();
storeContext.Setup(x => x.Items).Returns(dbSetMock.Object);
ItemRepo itemRepo = new ItemRepo(storeContext.Object);
string itemCode = itemRepo.GenerateItemCode();
Assert.AreEqual(itemCode, "CD345679");
}
这是上下文类
public class StoreContext : DbContext, IDisposable
{
public StoreContext():base("DefaultConnection")
{
}
public virtual IDbSet<Item> Items { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
当我使用IDbSet而不是DbSet时,我的应用程序性能下降。因为我不能使用如下
context.Items.Include("Promotions")//Cannot use Include with IDbSet
context.Items.AddRange(items)//cannot use AddRange with IDbSet
context.Items.RemoveRange(items)//cannot with IDbSet
所以我在上下文类中从IDbSet更改为DbSet,如下所示
public virtual DbSet<Item> Items { get; set; }
然后单元测试开始抛出错误。因为上下文类的项目不能用我嘲笑的方式来模拟。以下是错误的屏幕截图。
所以我在单元测试中从IDbSet更改为DbSet。然后错误变成这样。
如何为单元测试模拟上下文类的DbSet实体?
答案 0 :(得分:1)
问题更新后,我可以重现您的问题。你只是忘了转换到正确的界面IQueryable:
var dbSetMock = new Mock<DbSet<Item>>();
dbSetMock.As<IQueryable<Item>>().Setup(m => m.Provider).Returns(data.Provider);
dbSetMock.As<IQueryable<Item>>().Setup(m => m.Expression).Returns(data.Expression);
dbSetMock.As<IQueryable<Item>>().Setup(m => m.ElementType).Returns(data.ElementType);
dbSetMock.As<IQueryable<Item>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
如果您想知道为什么必须进行强制转换,以便可以设置提供程序,因为IQueryable的显式接口实现。更多信息:https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx