我应该如何在方法中测试 null 和/或空字符串参数?
类中的方法带有必须再次验证为 null 或空的字符串参数是很常见的,例如以下示例:
public class MyClass {
public void MyMethod(string param){
if(string.IsNullOrEmpty(param)){
throw new ArgumentNullException(...);
}
//...
}
}
很明显,对于两个(无效)值,该方法的行为是相同的。 这是一种很常见的情况,当谈到测试这些方法时,我总是怀疑如何去做。 我总是为这些情况创建两个单独的测试:
[TestClass]
public class Tests {
[TestMethod]
public void MyMethod_should_fail_if_param_is_null(){
//...
myclass.MyMethod(null);
//...
}
[TestMethod]
public void MyMethod_should_fail_if_param_is_empty(){
//...
myclass.MyMethod("");
//...
}
}
但我看到太多的冗余。 这些测试完全相同,唯一的区别是传递给方法的参数。 这让我非常困扰,因为我必须为每个字符串参数创建两个测试。 具有 3 个参数的方法将有 6 个测试,仅用于测试参数。
我认为这是测试这些参数的正确方法,但是如果我知道 99% 的字符串参数将以相同的方式进行验证,那么测试它们是否为 null(或空)并假设其中的行为不是更好吗?其他情况也会一样吗?
我想知道你对此有何看法。 我知道我问的更多的是技术意见而不是技术问题,但我认为测试社区可能对这种情况有一些有趣的说法。
谢谢你!
It is common to have classes with methods with string parameters that must be validated agains null or empty, such as this example:
public class MyClass {
public void MyMethod(string param){
if(string.IsNullOrEmpty(param)){
throw new ArgumentNullException(...);
}
//...
}
}
It's clear that the behavior of the method is the same for both (invalid) values. This is a very common situation, and when it comes to testing these methods, I always doubt about how to do it. I always create two separate tests for these cases:
[TestClass]
public class Tests {
[TestMethod]
public void MyMethod_should_fail_if_param_is_null(){
//...
myclass.MyMethod(null);
//...
}
[TestMethod]
public void MyMethod_should_fail_if_param_is_empty(){
//...
myclass.MyMethod("");
//...
}
}
But I see too much redundancy. Those tests are exactly the same, with the only difference being the parameter passed to the method. That bothers me very much, since I have to create two tests for each string parameter. A method with 3 parameters would have 6 tests only to test the parameters.
I think this is the right way of testing those parameters, but if I know that 99% of string parameters will be validated the same way, wouldn't it be better just test them for null (or empty) and assume that the behavior in the other case will be the same?
I would like to know what you think about this. I know what I'm asking is more a technical opinion than a technical question, but I think the testing community may have something interesting to say about this situation.
Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
就我个人而言,我考虑对所有参数使用一次测试。 这不遵循单元测试的正常教条,但它增加了测试的可读性(通过最小化专门用于相当重复的情况的测试代码量)并且没有太多缺点。 是的,如果测试失败,您不知道第一个失败之后的所有检查是否也会失败 - 但这在实践中真的是一个问题吗?
重要的一点是确保您有测试案例的捷径。 例如,您可能会编写如下内容(如果您的单元测试框架还没有):
然后您可以编写:
比使用单独的 try/catch 块,甚至使用
来完成每个测试要简洁得多ExpectedException
属性和多次测试。您可能需要在以下情况下重载:您还想验证在每种情况下都没有触及任何模拟对象(以检查是否避免了副作用),或者可能需要重载常见异常(例如
ArgumentNullException
)。对于单参数方法,您甚至可以编写一个方法来准确封装您需要的内容:
然后使用以下命令调用它:
... 对于具有单个参数但非 void 返回类型的方法,可能还可以使用另一个方法。
不过这可能有点过头了:)
Personally I'd consider using a single test for all of the parameters. That doesn't follow the normal dogma of unit testing, but it increases the readability of the tests (by minimizing the amount of test code which is dedicated to a pretty repetitive case) and doesn't have much in the way of downsides. Yes, if the test fails you don't know whether all of the checks after the first failing one will also fail - but is that really a problem in practice?
The important point is to make sure that you've got a short cut for testing the case. For instance, you might write something like this (if your unit test framework doesn't have it already):
Then you can write:
Much more concise than doing each one with an individual try/catch block, or even using an
ExpectedException
attribute and multiple tests.You might want overloads for cases where you also want to verify that in each case, no mocked objects have been touched (to check that side-effects are avoided) or possibly overloads for common exceptions like
ArgumentNullException
.For single-parameter methods you could even write a method to encapsulate exactly what you need:
then call it with:
... and maybe another one for methods with a single parameter but a non-void return type.
That's possibly going a bit far though :)
如果您使用 Java 和 JUnit,则可以使用此语法
If you use Java and JUnit you can use this syntax