关于单元测试的几个问题

时间:2010-08-30 19:03:42

标签: unit-testing testing tdd test-first

让我们假设我们正在设计一个Stack类测试优先(TDD):

public class Stack<T> {
    private T[] elements = new T[16];
    private int size = 0;
    ...
}

此Stack使用16号内部数组来存储其元素。它将正常工作,直到您需要添加第17个元素。因为我可能需要第17个元素,所以我决定将这个功能添加到我的Stack中,所以我开始考虑我可以为测试提供什么名称,以便添加该功能。这将是我第一个问题的主题。

我首先选择了以下形式的东西:

Should_Be_Able_To_Correctly_Increase_Its_Inner_Array_Size()

然后

Should_Handle_More_Items_Than_The_Default_Internal_Array_Size()
但是在考虑了一下后,我得出的结论是,以下内容可能会更合适:

Should_Double_Its_Size_Every_Time_Its_Full()

我的推理在第一种情况下必须这样做,我只说它的作用,但不是在什么时候。 在第二个,我说什么时候添加更多的项目,但我也在说明我是如何(内部)实现它的,这可能不正确。在我看来(我不确定我是否正确),我的测试应该是我的SUT与外部的可能交互,而不是内部如何实现。我是对的吗?

在我看来,第三种选择是最好的,因为它清楚地说明它的作用(增大尺寸 - 实际上是它的尺寸加倍),当它完成时(当它充满时)并且不会束缚我任何具体的实现(我以后可能想把它改成一个内部的ArrayList!)。

这引出了我的第二个问题:假设我为我的Stack类进行了所有单元测试,内部使用了一个数组并且它正常工作并且正如预期的那样,如果我的测试保持不变以后想要重构并将Array更改为ArrayList或任何其他类型的数据结构?或者测试以任何方式反映出来?我猜不是,但我不确定。

4 个答案:

答案 0 :(得分:3)

  

在我看来(我不确定我是谁   正确),我的测试应该是可能的   我的SUT与...的互动   外观,而不是如何   内部实施。我是对的吗?

你是对的。如果更改类的内部实现,则单元测试应保持不变。如果您在外部公开任何新内容,则应创建新的单元测试以考虑这些更改。

请记住,当您设计课程时,您不希望暴露任何指示其实施方式的内容。该班级的公共成员表明如何与之互动,现在它是如何在幕后工作的。

答案 1 :(得分:2)

我不确定如何通过单元测试来测试内部列表或数组大小。您无法通过Stack接口访问它。单元测试用于测试外部合同。如果您想测试实现细节,请尝试其他方法。

你的第二个问题的答案是肯定的,如果是单位测试,测试仍然应该通过。

答案 2 :(得分:2)

问问自己,你愿意为这堂课做些什么。

您或班级的消费者是否真正关心容量是否增加一倍,增加一倍或增加一千?如果是这样,您应该修改界面,以便他们可以指定用于增加容量的策略:

public Stack<T>(CapacityGrowthStyle capacityGrowthStyle) { ... }

如果没有,只需编写测试来记录容量并将其留在那里(下面X是您的基础数据结构的限制):

[Test]
public void Can_Handle_X_Items() { ... }

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void Cannot_Handle_More_Than_X_Items() { ... }

我会同样回答你的第二个问题:你的测试应该只反映基础数据结构,如果你的班级用户会关心它。

答案 3 :(得分:1)

我不确定您是否通过单元测试来测试内部列表或数组大小,因为您无法通过Stack接口访问它。有很多方法可以实现堆栈,有些是好的,有些是坏的,但正如Bernard所说,那些是内部实现。单元测试旨在测试面向外的功能。