使用IQueryable进行unit testing代码

我被要求为某些function编写一些unit testing,但坦率地说,我不太确定这个特定代码片段的需要或用处。 我总是试图质疑unit testing的必要性或有用性。

有问题的代码非常简单,并且可以使用很多。 基本上它是.Skip()和.Take()扩展方法的包装器。 在我看来,整个方法的合法性是值得怀疑的。

代码基本上是这样的:

public IQueryable Page(IQueryable query, int page, int size) { if(query == null) throw new ArgumentNullException("query"); if(page < 0) throw new ArgumentOutOfRangeException("page"); if(page < 0) throw new ArgumentOutOfRangeException("size"); return query.Skip(page * size).Take(size); } 

当然,我可以对预期的exception进行unit testing,但还有什么呢? 很可能是我错过了这一点,所以这有什么用呢?

你可以在这里测试很多东西:

  1. 检查是否有正确的防护(传递无效参数时抛出的exception)。
  2. 检查是否使用正确的参数调用了Skip
  3. 检查Take是否使用正确的参数调用。
  4. Take之前检查Skip被调用。

点2 – 4最好用模拟测试。 一个模拟框架在这里派上用场。
这种测试称为“基于交互的测试”。

您还可以通过使用带有数据的列表调用测试方法来使用“基于状态的测试”,并检查返回的数据是否是正确的子集。

第2点的测试可能如下所示:

 public void PageSkipsThePagesBeforeTheRequestedPage() { var sut = new YourClass(); var queryable = Substitute.For>(); sut.Page(queryable, 10, 50); queryable.Received().Skip(500); } 

此测试使用NSubstitute作为模拟框架。

您可以通过调用AsQueryable静态集合

 List dummyData = new List(); //Add data var result = Page(dummyData.AsQueryable(), 0, 10); //Perform assertions on result. 

如果你实际上只是想测试你的分页是否正常。

我敢肯定,非常需要测试这种方法。 首先,因为这个bug:

 if(page < 0) throw new ArgumentOutOfRangeException("page"); if(page < 0) throw new ArgumentOutOfRangeException("size"); 

你实际上没有检查size变量。

无论如何,不​​需要执行“集成”测试 - 您只需模拟您的IQueryable对象并执行unit testing。 (参见这个答案: 我如何模拟IQueryable )在我看来,测试这种方法是绝对正确的。

实际上,由于IQueryable可以封装底层数据存储 – 这是Entity Framework的可查询的情况 – 我们讨论的是集成测试

在我的情况下,如果我需要测试类似你的代码,我会在数据库中存储一些测试数据,以便以后查询。

由于我可以期待结果,我可以执行断言以检查测试方法是否返回了预期结果。

UPDATE

由于我看到与downvote和一些评论有些混淆,我想指出我已经回答了这个问题,考虑到答案被标记为Entity Framework ,我猜可查询是从DbSet获得的。