嘲笑使用Moq实现IQueryable的类
我花了一个晚上试图模拟一个实现IQueryable的对象:
public interface IRepo<T> : IQueryable<T>
{
}
我能想到的最好的是这样的:
var items = new Item[] {}.AsQueryable();
var repo = new Mock<IRepo>();
repo.Setup(r => r.GetEnumerator()).Returns(items.GetEnumerator());
repo.Setup(r => r.Provider).Returns(items.Provider);
repo.Setup(r => r.ElementType).Returns(items.ElementType);
repo.Setup(r => r.Expression).Returns(items.Expression);
有没有更简洁的方法来做同样的事情? 在IRepo中公开一个返回IQueryable的属性/方法和简单的模拟会更容易,如下所示:
repo.Setup(r => r.GetItems()).Returns(new Items[]{ }.AsQueryable());
但这不是我想要做的=)
这不是什么新鲜事,只是一个更干净的做法。 我也有仓库本身也是IQueryable的仓库,所以我需要同样的东西。 我基本上只是把你的代码放到我的测试项目的根级这样的扩展方法中,以使其可用于所有测试:
public static class MockExtensions
{
public static void SetupIQueryable<T>(this Mock<T> mock, IQueryable queryable)
where T: class, IQueryable
{
mock.Setup(r => r.GetEnumerator()).Returns(queryable.GetEnumerator());
mock.Setup(r => r.Provider).Returns(queryable.Provider);
mock.Setup(r => r.ElementType).Returns(queryable.ElementType);
mock.Setup(r => r.Expression).Returns(queryable.Expression);
}
}
这基本上只是提供了可重用性,因为你可能想要在几次测试中做到这一点,并且在每次测试中,它的意图都很清楚,并且混乱程度最低。 :)
符文的答案很棒,让我时刻知道如何去做。 小问题是,如果你在你的IQueryable上调用了两次IQueryable扩展方法(例如ToList()),那么你第二次不会返回结果。 这是因为统计员在最后,需要重新设置。 使用Rhinomocks我将GetEnumerator的实现更改为:
mock.Stub(r => r.GetEnumerator()).Do((Func<IEnumerator<T>>) (() => {
var enumerator = queryable.GetEnumerator();
enumerator.Reset();
return enumerator;
}));
希望能节省一些时间。
我喜欢符恩的答案。 这是一个通用的IQueryable版本:
public static void SetupIQueryable<TRepository, TEntity>(this Mock<TRepository> mock, IQueryable<TEntity> queryable)
where TRepository : class, IQueryable<TEntity>
{
mock.Setup(r => r.GetEnumerator()).Returns(queryable.GetEnumerator());
mock.Setup(r => r.Provider).Returns(queryable.Provider);
mock.Setup(r => r.ElementType).Returns(queryable.ElementType);
mock.Setup(r => r.Expression).Returns(queryable.Expression);
}
链接地址: http://www.djcxy.com/p/54059.html