模拟使用Moq实现IQueryable的类

Lef*_*une 37 c# unit-testing moq mocking

我花了一个晚上试图模拟一个实现IQueryable的对象:

public interface IRepo<T> : IQueryable<T>
{
}
Run Code Online (Sandbox Code Playgroud)

我能想到的最好的是这样的:

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);
Run Code Online (Sandbox Code Playgroud)

有没有更简洁的方法来做同样的事情?在IRepo中公开一个返回IQueryable的属性/方法会更容易,并且这样简单地模拟:

repo.Setup(r => r.GetItems()).Returns(new Items[]{ }.AsQueryable());
Run Code Online (Sandbox Code Playgroud)

但这不是我想做的事情=)

Run*_*sen 46

这不是什么新鲜事,只是一种更干净的方式.我也有存储库,其中存储库本身也是一个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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这基本上只是提供了可重用性,因为您可能希望在多个测试中执行此操作,并且在每个测试中它使意图清晰且最简单.:)


Rob*_*Rob 8

符文的答案很棒,让我省时间搞清楚如何做同样的事情.小问题是,如果你在IQueryable上调用一些IQueryable扩展方法两次(例如ToList()),那么第二次你将得不到任何结果.那是因为调查员在最后并且需要重置.使用Rhinomocks我将GetEnumerator的实现更改为:

mock.Stub(r => r.GetEnumerator()).Do((Func<IEnumerator<T>>) (() => { 
    var enumerator = queryable.GetEnumerator();
    enumerator.Reset();
    return enumerator;
}));
Run Code Online (Sandbox Code Playgroud)

希望能节省一些时间.

  • 这也为起订量节省了我的培根!`mockSet.As&lt;IQueryable&lt;MyEntity&gt;&gt;().Setup(m =&gt; m.GetEnumerator()).Returns(() =&gt; { var enumerator = queryable.GetEnumerator(); enumerator.Reset(); return enumerator; });` (2认同)

Mar*_*ood 6

我喜欢Rune的回答.这是一个通用的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);
}
Run Code Online (Sandbox Code Playgroud)