2014-05-02 229 views
2

我有一个函数遍历父对象的列表,并获取for-each循环中每个父对象的子对象。要获取子对象列表,该函数会调用另一个函数。这里是功能:如何测试嵌套的foreach循环?

public IEnumerable<IParentObject> GetParentAndChildObjects() 
{ 
    var parentObjects = new List<ParentObject>(); 

    foreach (var item in _dbRepository.GetParentObjects()) 
    { 
     var parentObject = new ParentObject() { Id = item.ID, Name = item.Name }; 
     foreach (var subItem in _dbRepository.GetChildObjects(item.ID)) 
     { 
      parentObjects.Children.Add(new ChildObject() { Id = subItem.ID, Name = subItem.Name }); 
     } 
    } 
    return parentObjects; 
} 

我该如何写这个函数的单元测试?我正在使用Moq进行嘲弄。

+2

offtopic:你永远添加'parentObject'到'parentObjects'。你在'parentObjects'上调用'Children'而不是新创建的'parentObject'。所以你的代码根本不能编译(除非你有'Children'属性的'List '实现)。 – MarcinJuraszek

+3

你模拟'_dbRepository'。 –

回答

0

事情是这样的:

var repo = new Mock<MyRepository>(); 
repo.Setup(r => r.GetParentObjects()).Returns(... a list with a couple of parent objects ...); 
repo.SetUp(r => r.GetChildObjects(... id of first parent ...)).Returns(... list of child objects ...); 
repo.SetUp(r => r.GetChildObjects(... id of secondparent ...)).Returns(... different list of child objects ...); 

var result = new MyClass(repo.Object).GetParentAndChildObjects(); 

... assertions to check 2 parents with appropriate children returned ... 
0

通常情况下,你将创造内循环功能(可能是一个很好的事情,无论如何,为便于阅读和嵌套)。然后,一旦该功能就位,您可以为其创建单元测试,就像您使用其他任何方法一样。

如果由于某种原因您不想使用"Extract Method" refactoring(可以使用Resharper或其他重构工具自动执行),恐怕您运气不好,因为单元测试需要有一个入口点来测试你不能在另一种方法的中间输入。

你可能会考虑的一件事,虽然它更多的维护,但有一个单元测试的调试版本和一个优化版本的循环内联,使用#if。如果您在.NET 4.5或更高版本,你可以简单地提取内环的方法和使用aggressive inlining of the method,而你没有的高维护的提取方法的(潜在的)损失或性能的开销。你可以使用

3

一种方法是测试内环以同样的方式将一个私有方法。也就是说,你不(至少不是直接)。

相反测试循环本身的,确认是由GetParentAndChildObjects返回的结果。

通过指定_dbRepository的测试双精度,您可以完全控制插入到parentObjects列表中的对象的详细信息。因此,您的测试可以验证返回的对象列表是否与预期一致。

Mark Seemann describes this approach well:

在已经回答了有关何时使用[存根以及何时使用嘲笑],几次的问题,我来到这个简单的规则,基于命令查询分离的语言( CQS):

  • 使用嘲笑的命令

  • 使用存根查询

这使得很多的意义,因为命令是所有有关的副作用,并嘲弄都是关于行为验证:即,副作用发生。另一方面,存根主要存在于“发出快乐的噪音”,而他们必须这样做的一种方式是在需要返回数据时从依赖关系返回数据。

+1

最佳答案imho,测试方法的功能,而不是底层的代码结构。 – Nexus