我应该使用不应在函数中传递的数据(无效输入)进行单元测试吗?
我正在尝试使用 TDD 进行编码实践。我想问我是否应该使用不应在函数中发生的数据进行测试,但该数据可能会破坏您的程序。
这是一个简单的例子来说明我的要求:
一个具有一个 INT 参数的 ROBOT 函数。在此函数中,我知道有效范围仅为 0-100。如果使用-1, 101,该函数将被中断。
function ROBOT (int num){
...
...
...
return result;
}
所以我决定了这个函数的一些自动化测试用例...
1. function ROBOT with input argument 0
2. function ROBOT with input argument 1
3. function ROBOT with input argument 10
4. function ROBOT with input argument 100
但是如果我会在调用函数 ROBOT 的其他函数中保护它,我应该为这个 ROBOT 函数编写带有输入参数 -1 或 101 的测试用例吗?
5. function ROBOT with input argument -1
6. function ROBOT with input argument 101
我不知道这是否有必要,因为我认为测试-1和101是多余的。如果确实有必要覆盖所有情况,我必须编写更多代码来保护-1和101。
所以共同点TDD的实践,你也会写-1和101的测试用例吗???
I am trying to use TDD for my coding practice. I would like to ask should I test with a data that should not happen in a function BUT this data may possibly break your program.
Here is one of a easy example to illustrate to what I ask :
a ROBOT function that has a one INT parameter. In this function I know that the valid range would only be 0-100. If -1, 101 is used, the function will be break.
function ROBOT (int num){
...
...
...
return result;
}
So I decided some automated test cases for this function...
1. function ROBOT with input argument 0
2. function ROBOT with input argument 1
3. function ROBOT with input argument 10
4. function ROBOT with input argument 100
But should I write test cases with input argument -1 or 101 for this ROBOT function IF I would guard that in my other function that call function ROBOT???
5. function ROBOT with input argument -1
6. function ROBOT with input argument 101
I don't know if it is necessary cause I think it is redundancy to test -1 and 101. And If it is really necessary to cover all the cases, I have to write more code to guard -1 and 101.
So in Common practice of TDD, will you write test case on -1 and 101 as well???
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
是的,您应该测试那些无效的输入。但是,如果您的语言具有可访问性修饰符并且
ROBOT()
是私有的,那么您不应该测试它;您应该只测试公共函数/方法。功能测试技术称为边界值分析。
如果您的范围是 0-100,则边界值为 0 和 100。您应该测试,至少:
在这种情况下:
您假设 -1 到 -无穷大以下的所有内容都表现相同,1-99 之间的所有内容表现相同,101 以上的所有内容表现相同。这称为等价分区。边界值之外和边界值之间的范围称为分区,您假设它们具有相同的行为。
您应该始终考虑使用 -1 作为测试用例,以确保如果参数不是强类型的,则负数和文本字符串不会发生任何有趣的情况。
Yes, you should test those invalid inputs. BUT, if your language has accessibility modifiers and
ROBOT()
is private you shouldn't be testing it; you should only test public functions/methods.The functional testing technique is called Boundary Value Analysis.
If your range is 0-100, your boundary values are 0 and 100. You should test, at least:
In this case:
You assume everything below -1 to -infinity behaves the same, everything between 1-99 behaves the same and everything above 101 behaves the same. This is called Equivalence Partitioning. The ranges outside and between the boundary values are called partitions and you assume that they will have equivalent behaviour.
You should always consider using -1 as a test case to make sure nothing funny happens with negative numbers and a text string if the parameter is not strongly typed.
如果预期结果是抛出带有无效输入值的异常,那么测试是否正确抛出异常是合适的。
编辑:
正如我在下面的评论中指出的,如果这些情况会破坏您的应用程序,您应该抛出异常。如果这些情况在逻辑上确实不可能发生,那么我会说不,你不需要抛出异常,也不需要测试用例来覆盖它。
请注意,如果您的系统已很好地组件化,并且此功能是一个组件,那么它现在在逻辑上不可能的事实并不意味着它在逻辑上永远是不可能的。它可能会以不同的方式使用。
If the expected outcome is that an exception is thrown with invalid input values, then a test that the exceptions get properly thrown would be appropriate.
Edit:
As I noted in my comment below, if these cases will break your application, you should throw an exception. If it really is logically impossible for these cases to occur, then I would say no, you don't need to throw an exception, and you don't need test cases to cover it.
Note that if your system is well componentized, and this function is one component, the fact that it is logically impossible now doesn't mean it will always be logically impossible. It may be used differently down the road.
您说如果参数无效,您的方法将引发异常。
所以,是的,你应该这样做,因为你应该测试是否引发异常。
You said your method will raise an exception if the argument is not valid.
So, yes you should, because you should test that the exception gets raised.
简而言之,如果它可以打破,那么你应该测试它。还要尽早验证数据。
答案取决于您是否控制传递给机器人的输入。如果 Robot 是内部类 (C#) ;值仅从公共类型 RobotClientX 流入。然后我将防护检查放入 RobotClientX 中,为其编写测试。我不会为机器人编写测试,因为无效值无法在中间实现。
例如,如果我将验证放在 GUI 中,以便在源处过滤掉所有无效值,那么我不会检查 GUI 下面的所有类中的无效值(除非我还公开了绕过 GUI 的公共 API )。
另一方面,如果机器人是公开可见的,即任何人都可以使用他们喜欢的任何值来调用机器人,那么我需要测试来记录它在给定特定类型输入的情况下的行为..无效是其中之一。例如,如果您传递超出范围的值,它将抛出 ArgumentException。
In short, if it can break, then you should test it. Also validate data at the earliest point possible.
The answer depends on whether you control the inputs passed to Robot. If Robot is an internal class (C#) ; values only flow in from RobotClientX which is a public type. Then I'd put the guard checks in RobotClientX, write tests for it. I'd not write tests for Robot, because invalid values cannot materialize in-between.
e.g. if I put my validations in the GUI such that all invalid values are filtered off at the source, then I don't check for invalid values in all classes below the GUI (Unless I've also exposed a public API which bypasses the GUI).
On the other hand, if Robot is publicly visible i.e. Anyone can call Robot with any value that they please, then I need tests that document it's behavior given specific kinds of input.. invalid being one of them. e.g. if you pass an out-of-range value, it'd throw an ArgumentException.
如果其他代码防止错误地调用该方法,并且没有其他人会编写代码来调用该方法,那么我认为没有理由使用无效值进行测试。对我来说,这似乎是浪费时间。
If other code guards against calling that method incorrectly, and no one else will be writing code to call that method, then I don't see a reason to test with invalid values. To me, it would seem a waste of time.
按契约编程的设计和实现风格引起人们注意这样一个事实:单个函数(方法)应该只负责某些事情,而不是所有事情。它调用(委托)以及调用它的其他函数也有责任。这种职责划分是将编程任务划分为可以单独执行的较小任务的核心。按契约编程的契约部分是,函数的规范说明了函数必须执行的操作当且仅当函数的调用者履行了调用者的职责按该规范。输入整数在[0,100]范围内的要求就是这样的要求。
现在,单元测试不应该测试实现细节。他们应该测试该功能是否符合其规范。这使得实现能够在不破坏测试的情况下进行更改。它使重构成为可能。
结合这两个想法,我们如何为给定某些特定无效输入的函数编写测试?我们应该检查函数的行为是否符合规范。但规范并没有说明在这种情况下该函数必须做什么。所以我们不能在无效函数调用后编写任何程序状态检查;该行为未定义。所以我们根本无法编写这样的测试。
The programming by contract style of design and implementation draws attention to the fact that a single function (method) should be responsible for only some things, not for everything. The other functions that it calls (delegates to) and which call it also have responsibilities. This partition of responsibilities is at the heart of dividing the task of programming into smaller tasks that can be performed separately. The contract part of programming by contract is that the specification of a function says what a function must do if and only if the caller of the function fulfills the responsibilities placed on the caller by that specification. The requirement that the input integer is within the range [0,100] is that kind of requirement.
Now, unit tests should not test implementation details. They should test that the function conforms to its specification. This enables the implementation to change without the tests breaking. It makes refactoring possible.
Combining those two ideas, how can we write a test for a function that is given some particular invalid input? We should check that the function behaves according to the specification. But the specification does not say what the function must do in this case. So we can not write any checks of the program state after the invalid function call; the behaviour is undefined. So we can not write such a test at all.
我的答案是,不,您不想要异常,您不希望让
ROBOT()
检查超出范围的输入。客户端应该表现得很好,以至于他们不会传递垃圾值。您可能想要记录这一点 - 只是说客户端必须小心他们传递的值。
此外,您将从哪里获取无效值?好吧,用户输入或者通过将字符串转换为数字。但在这些情况下,应该由转换例程执行检查并提供有关值是否有效的反馈。应保证这些值在接近
ROBOT()
之前很长时间都有效!My answer is that, no, you don't want exceptions, you don't want to have to have
ROBOT()
check for out of range input. The clients should be so well behaved that they don't pass garbage values in.You might want to document this - Just say that clients must be careful about the values they pass in.
Besides where are you going to get invalid values from? Well, user input or by converting strings to numbers. But in those cases it should be the conversion routines that perform the checks and give feedback about whether the values are valid or not. The values should be guaranteed to be valid long before they get anywhere near
ROBOT()
!