如何让这个单元测试独立?

时间:2013-09-26 12:40:39

标签: java unit-testing

单元测试最佳实践之一是使每个测试独立于所有其他测试。假设我想测试BoundedPriorityBlockingQueue自定义类的add()方法:

public void testAdd() {
    BoundedPriorityBlockingQueue q = BoundedPriorityBlockingQueue();
    q.add(1);
    assertEquals(1, q.size());
}

正如您所看到的,当前testAdd使用size()方法,因此它依赖于它,但是当size()被破坏时我不希望testAdd()失败。在这种情况下,最佳做法是什么?

4 个答案:

答案 0 :(得分:11)

  

在这种情况下,最佳做法是什么?

请记住,测试是为了服务你,而不是相反。

如果出现严重错误,你的测试会破裂吗?是。

问题出在哪里?可能是因为使用size的任何内容都会失败。

这项测试是否会推动您进行不太可测试的设计?否。

这是测试add的最简单方法吗?面对不断变化的实施细节,这是一种强大的方法吗?大概。 (我想测试你可以再次获得价值,请注意。)

是的,它有点测试同一类的两个部分 - 但我真的不认为这是一个问题。我看到很多关于测试的教条(“只测试公共API,总是使用AAA”等) - 根据我的经验,你应该用健康的实用主义来缓和教条主义。

答案 1 :(得分:6)

目标是使所有测试方法独立于其他 test 方法,并且此方法是独立的。无论你在其他测试方法中做什么,它都会根据被测试类中方法的操作而通过或失败。

如果测试中的其他方法被破坏,则此测试失败是正常的。如果size()被破坏,您将有多个测试失败(这一个和明确测试size()的失败),因此问题显而易见。如果add()被破坏,则只有此测试失败(以及依赖add())的任何其他方法。

答案 2 :(得分:2)

正如其他人已经说过的那样,如果你的size方法被破坏,那么测试就会失败,所以你有理由去调查并理解为什么会发生这种情况。

无论如何,如果您仍然对测试之间具有这种独立性感兴趣,那么您可以选择白盒测试策略:我猜你的BoundedPropertyBlockingQueue内部使用任何一个java.util集合,您依赖的其他提供程序(Guava,Apache Collections等)的数组或集合实现,因此您无需验证这些结构是否按预期工作。

因此,将内部结构定义为protected,将测试类放在具有相同名称的包中,而不是依赖于size方法的实现,进入BoundedPropertyBlockingQueue

BoundedPriorityBlockingQueue q = BoundedPriorityBlockingQueue();
q.add(1);
assertEquals(1, q.contents.size());  // assuming that `contents` attribute is a collection.

主要缺点是,如果您的队列内部实现发生变化,您需要更改测试,同时使用之前的测试方法,您将不需要。

IMO我会选择你当前的实现,更少耦合,最后,实现其目标。

答案 3 :(得分:1)

进行这样的交叉测试没有任何问题 - 有些方法倾向于成对生成(添加/删除,入队/出队等),没有其补充部分测试一个方法没有意义

但是,我会更多地考虑一下客户端(类用户)将如何使用add方法。最有可能不会调用add来确定是否更改了大小,而是稍后检索添加的项目。也许你的测试看起来应该更像这样:

BoundedPriorityBlockingQueue q = new BoundedPriorityBlockingQueue();
QueueItem toAdd = 1;
QueueItem added = q.dequeue();
assertEquals(toAdded, added);

除此之外,您还可以在上面的测试中添加guard assert(以确保队列不会从已添加的某些项开始)或更好 - 包括保证初始状态的单独测试(大小为0,出队返回null / throw)。