单元测试正确的数据结构创建

时间:2009-09-12 12:34:55

标签: java unit-testing tree tdd

如何测试数据结构是否正确构建?我正在实现一种修改后的基数树,并且想知道如何检查数据结构是否正确构建。

考虑TreeNode {String, Int}个节点的树。 您总是希望将新子节点附加到值的最深节点等于0,如下例所示:

Root, 0
- Child_1, 5
- Child_2, 0
   - Child_3, 1

问题是,如果树结构按照您的意愿建立,如何进行单元测试? TreeNode只有一个方法,即insert

到目前为止,我的想法是编写TreeVisitor,它将遍历树并将每个节点转换为字符串。 上面例子中的树可能如下所示:

[Root, 0 [Child_1, 5][Child_2, 0 [Child_3, 1]]]

知道构建树的算法,如果我知道我要插入哪些元素,我可以手动创建这样的字符串。我的单元测试看起来像这样(使用相同的例子)。

TreeNode root = new TreeNode("Root", 0);
root.insert(new TreeNode("Child_1", 5));
root.insert(new TreeNode("Child_2", 0));
root.insert(new TreeNode("Child_3", 1));
TreeVisitor visitor = new TreeVisitor();
String expected = "[Root, 0 [Child_1, 5][Child_2, 0 [Child_3, 1]]]";
asssertEquals(expected, visitor.visit(root));

我觉得这不是最好的方法。首先,一旦访问者更改,所有测试都将失败(只需将更改[ ]更改为( ))。此外,这种方法允许我测试相当小的树(尽可能大,我可以手动计算)。你会如何测试更大的?

一般问题是,如何编写测试检查数据结构是否正确构建

我认为我可能会把整个测试想法弄错了,因为我从十二个教程开始,人们测试.Sum(a,b)是否按预期工作:-)

3 个答案:

答案 0 :(得分:3)

这看起来像是测试驱动设计的一个案例。仅具有“插入”方法的接口是不可测试的,因为它也是不可用的。建造一棵树,无法看到或做任何事情,你建造的树不会让你到任何地方。

确定您希望客户端访问树的方式(访问方法,访问者界面等)。然后通过它们进行测试。

如果存在内部复杂性,您无法轻松通过公共接口(即树更像是Java TreeMap而不是您在TreeView中放置的树的类型),您可以使用:

  • 断言和不变量
  • 像暴露的东西 debugVerifyTree方法。
  • 暴力:插入36542个伪随机物品,使用覆盖工具检查是否涵盖所有情况。

无论哪种方式,无论何时编写测试,请确保提出“此代码的任何客户是否会关注此测试是否失败?”的问题。如果没有,删除它。

答案 1 :(得分:1)

也许你可以用你自己的子类替换单元测试中的 TreeNode 的实现,这些子类公开了让你以递归方式检查当前子集的方法。这些方法将添加到 TreeNode 实现中以帮助单元测试,并且不会替换其现有功能,因此您仍然可以进行有效测试。

答案 2 :(得分:1)

我通常最终做的是制作指示您正在测试的东西的值或名称。因此,对于树,名称可能表示深度和子索引。

TreeNode root = new MyTreeNode("0.0", 0);
root.insert(new MyTreeNode("1.0", 5));
root.insert(new MyTreeNode("1.1", 0));
root.insert(new MyTreeNode("2.0", 1));
verify(root, 0, 0);
...
public void verify(TreeNode node, int depth, int index) {
   verifyName(node, depth, index);
   int numChildren = node.getChildCount();
   depth++;
   for (int i = 0; i < numChildren; i++) {
      verify(node.getChildAt(i), depth, i);
   }
}
public void verifyName(TreeNode node, int depth, int index) {
   StringBuilder expectedName = new StringBuilder();
   expectedName.append(depth).append('.').append(index);
   assertEquals("Tree node not in expected place",
                expectedName.toString(), node.getName());
}

现在我可以想象测试一棵相当大的树。如果递归的深度是一个问题,那么你可以使用堆栈来解包递归方法。

public void verify(TreeNode root) {
   Stack<TreeNode> toBeVerified = new Stack<TreeNode>();
   verifyName(root, 0, 0);
   toBeVerified.push(root);

   while(!toBeVerified.isEmpty()) {
     TreeNode node = toBeVerified.pop();
     int depth = getDepth(node.getName()) + 1;
     int numChildren = node.getChildCount();
     for (int i = 0; i < numChildren; i++) {
        verifyName(node, depth, i);
        toBeVerified.push(node);
     }
   }
}
public int getDepth(String name) {
   return Integer.parseInt(name.substring(0, name.indexOf('.')));
}