使用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,但还有什么呢? 很可能是我错过了这一点,所以这有什么用呢?
你可以在这里测试很多东西:
- 检查是否有正确的防护(传递无效参数时抛出的exception)。
- 检查是否使用正确的参数调用了
Skip
。 - 检查
Take
是否使用正确的参数调用。 - 在
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
获得的。