2009-05-30 58 views
8

这是常见的有与字符串参数的方法,必须验证agains为零或为空,如本实施例中的类:我应该如何在方法中测试空和/或空字符串参数?

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%的字符串参数将以同样的方式进行验证,那么测试它们为空(或空)并假设它们会更好在另一种情况下的行为将是相同的?

我想知道你对此有何看法。我知道我问的是技术问题而不是技术问题,但我认为测试社区可能对这种情况有一些有趣的看法。

谢谢!

回答

11

我个人认为考虑使用单个测试的所有参数。这不符合单元测试的正常教条,但是它增加了测试的可读性(通过最小化专用于相当重复的情况的测试代码量)并且没有太多的缺点。是的,如果测试失败,您不知道第一次失败后的所有检查是否也会失败 - 但是真的是在实践中是否存在问题?

重要的一点是确保你有一个捷径来测试案例。比如,你可以写这样的事情(如果你的单元测试框架,没有它的话):

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),您可能需要重载。

对于单参数的方法,你甚至可以写一个方法来封装你所需要的东西:

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); 
} 

...也许再一个方法只有一个参数,但是一个非空的返回类型。

这可能会有点远,虽然:)

+0

谢谢你的快速反应! 我已经创建了我自己的ExpectException版本(你可以在这里查看http://gerardocontijoch.wordpress.com/2008/12/02/uso-de-expectedexceptionattribute-para-testear-excepciones/),并使用它在这些情况下。不能没有它:P 我喜欢你提出的解决方案,我想过,但正如你所说,“这不符合单元测试的正常教条”,我只想跟随它,你知道,习惯良好的做法。毕竟,我可能会选择这个解决方案。让我们来看看还有什么其他的想法... – 2009-05-30 21:49:17

+1

事情是,我不相信遵循教条,把实用主义推出窗外*是一个很好的习惯:)这是值得的*知道*的教条,但随后有意识地忽略它对于特定的情况,我们已经权衡了利弊,并发现它不起作用。 – 2009-05-30 22:15:01

-2

如果您使用Java和JUnit你可以使用这个语法

@Test(expected = IllegalArgumentException.class) 
public void ArgumentTest() { 
    myClass.MyMethod(""); 
    myClass.MyMethod(null); 
} 
相关问题