测试驱动开发:为私有/受保护变量编写测试
我正在学习 TDD,我有一个关于私有/受保护变量的问题。我的问题是:如果我想测试的函数正在私有变量上运行,我应该如何测试它?
这是我正在使用的示例:
我有一个名为 Table 的类
包含一个名为 internalRepresentation
的实例变量,它是一个 2D 数组。我想创建一个名为 multiplyValuesByN
的函数,它将 2D 数组中的所有值乘以参数 n
。
所以我为它编写了测试(用 Python):
def test_multiplyValuesByN (self):
t = Table(3, 3) # 3x3 table, filled with 0's
t.set(0, 0, 4) # Set value at position (0,0) to 4
t.multiplyValuesByN(3)
assertEqual(t.internalRepresentation, [[12, 0, 0], [0, 0, 0], [0, 0, 0]])
现在,如果我将 internalRepresentation
设置为私有或受保护,则该测试将不起作用。我应该如何编写测试,使其不依赖于 internalRepresentation
,但在调用 multiplyValuesByN
后仍然测试它看起来是否正确?
I'm learning TDD, and I have a question about private / protected variables. My question is: If a function I want to test is operating on a private variable, how should I test it?
Here is the example I'm working with:
I have a class called Table
that contains an instance variable called internalRepresentation
that is a 2D array. I want to create a function called multiplyValuesByN
that multiplies all the values in the 2D array by the argument n
.
So I write the test for it (in Python):
def test_multiplyValuesByN (self):
t = Table(3, 3) # 3x3 table, filled with 0's
t.set(0, 0, 4) # Set value at position (0,0) to 4
t.multiplyValuesByN(3)
assertEqual(t.internalRepresentation, [[12, 0, 0], [0, 0, 0], [0, 0, 0]])
Now, if I make internalRepresentation
private or protected, this test will not work. How am I supposed to write the test so it doesn't depend on internalRepresentation
but still tests that it looks correct after calling multiplyValuesByN
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您不应该依赖于对象的内部表示。这就是为什么它被标记为私有或受保护的原因。考虑调用 t.multiplyValuesByN(3) 时对 t 进行了哪些可观察到的更改。然后,测试您可以观察到的内容。
You should not depend on the internal representation of an object. That's why it is marked as private or protected. Consider what observable changes are made to t when you call t.multiplyValuesByN(3). Then, test on what you can observe.
如果是内部的,那么课堂之外的任何人都无所谓,包括测试。
在 TDD 中,你正在设计类的 API,未来的客户端也只能看到类的可观察行为。
我知道这说起来容易做起来难。
在测试中,您经常会看到重复出现的模式:设置 - 操作 - 检查( - 拆卸)
设置阶段负责使对象进入前置条件状态。
检查阶段应该通过类的可观察行为来验证后置条件。如果不可见状态永远不会且无处显示,那么存储它就没有意义。
If it is internal, then it is nobodys business outside the class and that includes the tests.
In TDD you are designing the API of your classes and the future clients also can only see the observable behavior of the class.
I know this is easier said than done.
In test you often see a pattern reoccuring : setup - operate - check (- teardown)
The setup phase is responsible to bring the object in the preconditions state.
The check phase should verify the postconditions through observable behavior of the class. It makes no sense to store invisible state, if it never and nowhere comes out.
其他人已经发布了很好的答案,但恕我直言,未能强调一件事:设计方面(尽管彼得·蒂勒曼斯提到了这一点)。所以我对此添加一些解释。
在进行 TDD 时,您可以有效地测试 API 的设计和实现。如果您发现方法调用的结果很难或不可能从外部看到,这几乎总是表明您的类接口设计得不好。如果为你的类编写测试很困难,那么在现实生活中使用它通常也很困难 - 你的单元测试实际上是你的类的第一个客户。因此,如果您发现测试用例难以使用您的类接口,您应该考虑返回并重新设计您的 API,以使其更易于使用(如果可能,不影响封装)。
Others have posted good answers, but IMHO failed to emphasize one thing: the design aspect (although Peter Tillemans mentioned it). So I add a bit of an explanation on this.
When doing TDD, you are effectively testing the design of your API as well as the implementation. If you find that the result of a method call is difficult or impossible to see from outside, this is almost always a sign that your class interface is not designed well. If it is difficult to write tests for your class, it will usually be difficult to use it in real life too - your unit tests are in effect the first clients of your class. So if you see that a test case has difficulty using your class interface, you should consider going back and redesigning your API to make it easier to use (not compromising encapsulation, if possible).
不要测试私有变量/状态。您的测试应确认被测单元符合其规范,并且该规范由其接口确定。因此,您的测试应该根据测试单元的输入来编写,并验证输出是否符合您的预期。
您希望能够更改被测单元的实现(例如,出于效率原因),并确认其按预期工作。因此在这种情况下检查私有状态会造成困难。
Don't test for private variables/state. Your tests should confirm that the unit under test conforms to its specification, and that specification is determined by its interface. So your test should be written in terms of the inputs to your test unit, and verify that the output matches what you expect.
You want to be able to change the implementation of the unit under test (for, say, efficiency reasons) and yet confirm that it works as expected. So checking private state would cause difficulties in this situation.