关于单元测试的几个问题
假设我们正在设计一个测试优先 (TDD) 的 Stack 类:
public class Stack<T> {
private T[] elements = new T[16];
private int size = 0;
...
}
该 Stack 使用大小为 16 的内部数组来存储其元素。它会正常工作,直到您需要添加第 17 个元素。由于我可能需要第 17 个元素,因此我决定将该功能添加到我的堆栈中,因此我开始考虑可以为必须添加该功能的测试起什么名称。这将是我第一个问题的主题。
我首先选择了以下形式的内容:
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 类进行了所有单元测试,并且它工作正常且符合预期,如果我以后想要,我的测试是否应该保持不变重构并将数组更改为 ArrayList 或任何其他类型的数据结构?或者测试是否应该以某种方式反映这一点?我猜不会,但我不确定。
Let's assume we are designing a Stack class test-first (TDD):
public class Stack<T> {
private T[] elements = new T[16];
private int size = 0;
...
}
This Stack makes use of a size 16 internal array to store its elements. It will work fine until you need to add a 17th element. As I might need a 17th element, I decided to add that functionality to my Stack, so I started thinking about what name I could give to the test that'd make have to add that functionality. That will be the subject of my first question.
I first chose something of the form of:
Should_Be_Able_To_Correctly_Increase_Its_Inner_Array_Size()
and then
Should_Handle_More_Items_Than_The_Default_Internal_Array_Size()
but after thinking for a bit I came to the conclusion that maybe something like the following would be more apropriate:
Should_Double_Its_Size_Every_Time_Its_Full()
My reasoning would have to do that in the first case, I am saying only what it does, but not when.
In the second, I am saying when to add more items, but I am also stating how I'm thinking of achieving it (internally), which may not be correct. In my view (I'm not sure I am correct), my tests should the possible interactions of my SUT with the exterior, and not on how it is implemented internally. Am I right?
It looks to me that the 3rd options is the best, as it clearly states what it does(grow in size -- in fact, double its size), when it does(when it's full) and doesn't ties me to any specific implementation (I could maybe later want to change it to an internal ArrayList!).
Which leads me to my second question: Assuming I did all the Unit-Tests for my Stack class that uses internally an Array and it works fine and as expected, should my tests remain intact if I later want to refactor and change the Array to an ArrayList or any other kind of data-structure? Or should the tests in any way reflect that? I'd guess no, but I'm not sure.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你是对的。如果更改类的内部实现,单元测试应保持不变。如果您向外部公开任何新内容,则应该创建新的单元测试来解释这些更改。
请记住,当您设计类时,您不想暴露任何表明其实现方式的内容。类的公共成员指示如何与其交互,现在它是如何在幕后工作的。
You are correct. If you change the internal implementation of your class, the unit tests should remain the same. If you expose anything new externally, you should create new unit tests to account for these changes.
Remember that when you're designing your class you don't want to expose anything that indicates how it was implemented. The class' public members indicate how to interact with it, now how it works behind the scenes.
我不确定如何通过单元测试来测试内部列表或数组大小。您无法通过 Stack 接口访问它。单元测试用于测试外部合约。如果您想测试实现细节,请尝试其他方法。
第二个问题的答案是肯定的,如果是单元测试,测试仍然应该通过。
I am not sure how you can the test the internal list or array size through a unit test. You can't access it through the Stack interface. Unit testing is for testing external contracts. If you want to test implementation details then try something else.
The answer to your 2nd question is yes, the test should still pass, if it's a unit test.
问问自己你愿意为这门课做出什么承诺。
你或班级的消费者真的关心容量是加倍、增加一倍还是增加一千吗?如果是这样,您应该修改接口,以便他们可以指定用于增加容量的策略:
如果不是,只需编写测试来记录容量并保留它(其中下面的
X
是您的基础数据结构的限制):我会类似地回答你的第二个问题:如果你的类的用户关心它,你的测试应该只反映底层数据结构。
Ask yourself to what you are willing to commit for this class.
Do you or the class' consumers really care whether the capacity doubles, increments by one, or increments by one thousand? If so, you should modify the interface so that they can specify the strategy used to increase capacity:
If not, just write tests to document the capacity and leave it at that (where
X
below is your underlying data structure's limit):I'd answer your second question similarly: your tests should only reflect the underlying data structure if your class' users will care about it.
我不确定您是否应该通过单元测试来测试内部列表或数组大小,因为您无法通过 Stack 接口访问它。实现堆栈的方法有很多,有好有坏,但正如伯纳德所说,这些都是内部实现。单元测试旨在测试面向外部的功能。
I'm not sure if you should test the internal list or array size through a unit test, since you cannot access it through the Stack interface. There are many ways to implement a stack, some good, and some bad, but as Bernard stated, those are internal implementations. Unit tests are designed to test outward facing functionality.