我对Unit Testing和Moq很新,但我正在尝试使用Moq和MSTest为通用存储库设置单元测试。我确定有很多事情我可能做错了,但我真的可以使用帮助来测试我的通用存储库的基于表达式的参数。具体来说,我似乎无法让我的模拟存储库返回一个预期的对象列表这里是代码:
上下文
public class OrderContext : DbContext, IDisposable
{
public virtual DbSet<Order> Orders { get; set; }
public virtual void Commit()
{
base.SaveChanges();
}
}
存储库接口/存储库
public interface IRepository<T> where T : class
{
IEnumerable<T> GetManyBySearch(Func<T, bool> where);
}
public class RepositoryBase<T> : IRepository<T> where T : class
{
private OrderContext _db;
private DbSet<T> _dbSet;
public RepositoryBase(OrderContext db)
{
_db = db;
_dbSet = _db.Set<T>();
}
// Get many records by search
public virtual IEnumerable<T> GetManyBySearch(Func<T, bool> where)
{
return _dbSet.Where(where).AsQueryable();
}
}
...在我的单元测试中,理想情况下我可以设置类似于this one的测试,只是我希望我的存储库返回基于内存对象数据的子集。表达式被传递给GetManyBySearch()方法。 目前,我的模拟存储库正在返回整个数据集,无论传递的表达式是什么。这是一个例子:
单元测试
[TestMethod]
[TestCategory("Repository Tests")]
public void Order_Get_Many_By_Search()
{
Mock<OrderContext> mockDb = new Mock<OrderContext>();
Mock<RepositoryBase<Order>> mockRepo = new Mock<RepositoryBase<Order>>(mockDb.Object);
var data = new List<Order>()
{
new Order { OrderId = 1, OrderNumber = 111, OrderDate = DateTime.Now },
new Order { OrderId = 2, OrderNumber = 222, OrderDate = DateTime.Now },
new Order { OrderId = 3, OrderNumber = 222, OrderDate = DateTime.Now }
}.AsQueryable();
var expectedResults = data.Where(m => m.OrderNumber == 222);
var mockSet = new Mock<DbSet<Order>>();
mockSet.As<IQueryable<Order>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Order>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Order>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Order>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
mockDb.Setup(m => m.Set<Order>()).Returns(mockSet.Object);
mockRepo.Setup(m => m.GetManyBySearch(It.IsAny<Func<Order, bool>>()))
.Returns(mockSet.Object.AsQueryable());
List<Order> results = mockRepo.Object.GetManyBySearch(m => m.OrderNumber == 222).ToList(); // This returns the entire "data" dataset
mockRepo.Verify(m => m.GetManyBySearch(It.IsAny<Func<Order, bool>>()), Times.Once());
Assert.AreEqual(2, results.Count()); // This fails :(
}
非常感谢任何帮助。提前谢谢。
答案 0 :(得分:3)
我怀疑测试是否在指示的行上失败,因为您的示例数据有3个元素并且您断言它包含2:
var data = new List<Order>()
{
new Order { OrderId = 1, OrderNumber = 111, OrderDate = DateTime.Now },
new Order { OrderId = 2, OrderNumber = 222, OrderDate = DateTime.Now },
new Order { OrderId = 3, OrderNumber = 222, OrderDate = DateTime.Now }
}.AsQueryable();
// <snip>...
Assert.AreEqual(2, results.Count());
但是,更大的问题是,在您的示例中,您实际上是在嘲笑您要测试的方法:
Mock<RepositoryBase<Order>> mockRepo = new Mock<RepositoryBase<Order>>(mockDb.Object);
// <snip>...
List<Order> results = mockRepo.Object.GetManyBySearch(m => m.OrderNumber == 222).ToList();
因此,您不会测试任何生产代码。相反,您只是测试模拟对象将执行您告诉他们的操作。
将模拟的存储库替换为实际实例,并将所有其他模拟对象注入其中。这将是一个很好的测试,GetManyBySearch
方法返回您期望的结果。