通常使用带有字符串参数的方法的类必须再次验证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%的字符串参数将以相同的方式验证,那么测试它们是否为空(或为空)并不是更好在另一种情况下的行为会是一样的吗?
我想知道你对此的看法。我知道我所要求的更多是技术意见而不是技术问题,但我认为测试社区可能会对这种情况有所了解。
谢谢!
答案 0 :(得分:12)
就我个人而言,考虑对所有参数使用单个测试。这不遵循单元测试的正常教条,但它增加了测试的可读性(通过最小化专用于非常重复的情况的测试代码的数量)并且没有太多的缺点。是的,如果测试失败,你不知道第一次失败之后的所有检查是否也会失败 - 但实际上确实是一个问题吗?
重要的是要确保你有一个捷径来测试案件。例如,你可能会写这样的东西(如果你的单元测试框架还没有):
public static void ExpectException<T>(Action action) where T : Exception
{
try
{
action();
Assert.Fail("Expected exception " + typeof(T).Name);
}
catch (T exception)
{
// Expected
}
}
然后你可以写:
[Test]
public void MyMethodFailsWithInvalidArguments()
{
ExpectException<ArgumentNullException>(() => myClass.MyMethod(null));
ExpectException<ArgumentException>(() => myClass.MyMethod(""));
}
比使用单独的try / catch块,甚至使用ExpectedException
属性和多个测试更简洁。
对于您还想要验证在每种情况下都没有触及任何模拟对象(以检查是否避免副作用)或可能是ArgumentNullException
等常见异常的重载的情况,您可能需要重载。 / p>
对于单参数方法,您甚至可以编写一个方法来准确地封装您需要的方法:
public void ExpectExceptionForNullAndEmptyStrings(Action<string> action)
{
ExpectException<ArgumentNullException>(() => action(null));
ExpectException<ArgumentException>(() => action(""));
}
然后用:
来调用它[Test]
public void MyMethodFailsWithInvalidArguments()
{
// This *might* work without the
ExpectExceptionForNullAndEmptyStrings(myClass.MyMethod);
}
...也许是另一个用于具有单个参数但是非void返回类型的方法。
虽然可能会有点远:)
答案 1 :(得分:-3)
如果您使用Java和JUnit,则可以使用此语法
@Test(expected = IllegalArgumentException.class)
public void ArgumentTest() {
myClass.MyMethod("");
myClass.MyMethod(null);
}