3

我被要求为某些功能编写一些单元测试,但坦率地说,我不太确定对这段特定代码这样做的必要性或有用性。我绝不会试图质疑一般单元测试的必要性或有用性。

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

代码基本上是这样的:

public IQueryable<T> Page(IQueryable<T> 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);
}

当然我可以对预期的异常进行单元测试,但是还有什么呢?很可能是我错过了重点,所以这是怎么回事?

4

4 回答 4

3

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

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

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

于 2012-12-03T15:28:59.000 回答
2

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

  1. 检查适当的防护(传递无效参数时引发的异常)。
  2. 检查是否Skip使用正确的参数调用。
  3. 检查是否Take使用正确的参数调用。
  4. 检查Skip之前调用Take的。

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

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

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

public void PageSkipsThePagesBeforeTheRequestedPage()
{
    var sut = new YourClass();
    var queryable = Substitute.For<IQueryable<int>>();

    sut.Page(queryable, 10, 50);

    queryable.Received().Skip(500);
}

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

于 2012-12-03T15:30:55.870 回答
0

事实上,由于IQueryable<T>可能封装了一个底层数据存储——实体框架的可查询对象就是这种情况——我们正在谈论集成测试

就我而言,如果我需要测试类似你的代码的东西,我会在数据库中存储一些测试数据以供以后查询。

因为我可以预期结果,所以我可以执行一个断言来检查测试的方法是否返回了预期的结果。

更新

由于我对不赞成票和一些评论感到有些困惑,因此我想指出,考虑到答案被标记为实体框架这一事实,我已经回答了这个问题,并且我猜可查询是从DbSet.

于 2012-12-03T15:27:59.967 回答
0

我敢肯定,非常需要测试这种方法。首先,由于错误:

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

实际上,您并没有检查 size 变量。

无论如何,没有必要执行“集成”测试——您可以简单地模拟您的 IQueryable 对象并执行单元测试。(请参阅此答案:我如何模拟 IQueryable<T>)在我看来,测试此方法是绝对正确的。

于 2012-12-03T15:35:10.683 回答