2013-08-26 19 views
2

考虑以下方法负面测试 - 我应该期待确切的例外吗?

public void Foo(string str) 
{ 
    if (str == null) 
     throw new ArgumentNullException("str"); 

    if (str.Length != 5) 
     throw new MyException(); 
} 

假设我想为它编写像这样一个负测试:

public void TestFoo() 
{ 
    try 
    { 
     Foo(null); //this could be an remote call (e.g. WCF) 
     Assert.Fail("Expected ArgumentNullException"); 
    } 
    catch (ArgumentNullException) {} //should this be "Exception" instead? 

    try 
    { 
     Foo("four"); //this could be an remote call (e.g. WCF) 
     Assert.Fail("Expected MyException"); 
    } 
    catch (MyException) {} //should this be "Exception" instead? 
} 

在我看来,那醒目如上一个特定的异常是一个实现细节,这可能使测试变得脆弱并且与实现(而不是接口)耦合。显然MyException可能会改变一天,但即使是ArgumentNullException也可能被封装在一些其他异常(例如未来的WCF行为)中。通常,测试知道“四个”应该失败,而这就是所关心的 - 失败。

例外情况(没有双关语意)或许应该在异常被转换成被传递给用户的东西的情况下,如用户友好的信息(例如,它被映射到用户名已经采取UserNameTakenException ,尝试不同的一个)。在这种情况下,您需要确保传达正确的错误。即使这样,它也有点问题,因为它意味着每种可能的用户错误都会有不同类型的异常,但这可能不会太糟糕(通常不会太多)。

我的思路是否有意义?我是否应该在不涉及面向用户的异常的测试用例中捕获通用的Exception

+1

你不会在TestFoo中捕获异常。您将该方法归入预期的例外。 – phillip

+2

您可能会因为基于观点而大吃一惊,但在我看来它非常有意义 - 在特定情况下抛出的异常是方法调用/ API的合同的一部分,因此应该通过测试来保护。 –

+0

我想这取决于测试框架,虽然...如:Assert.Throws (()=> wmd.DoItNow()); – phillip

回答

3

简单地写至少4次测试:

[Test] 
[ExpectedException(typeof(ArgumentNullException))] 
public void TestFooForNull() 
{ 
    Foo(null); 
} 


[Test] 
[ExpectedException(typeof(MyException))] 
public void TestFooForInvalidSizeTooShort() 
{ 
    Foo("1234"); 
} 


[Test] 
[ExpectedException(typeof(MyException))] 
public void TestFooForInvalidSizeTooLong() 
{ 
    Foo("123456"); 
} 


[Test] 
public void TestFoo() 
{ 
    Foo("12345"); 
} 

当编写单元测试,这是最好的治疗每次测试一个特定的情况下。

+2

罗伊,感谢你的回答,分离可能是更好的选择,但这不是问题。尽管我收集到了您的代码,但您仍支持这样的观点:应该预期确切的例外情况,这与收到的其他答复是内联的。 –

0
> should I expect the exact exception? 
    > ... 
    > Should I indeed catch the generic Exception in test cases that 
    > don't involve user-facing exceptions ? 

在dotnet中,捕获通用的Exception并不是一个好主意,因为它也会捕获AssertionException。我认为它也与java一样

public void ThisTestWillNeverFail() 
{ 
    try 
    { 
     Assert.Fail("some error message"); 
    } 
    catch (Exception) 
    { 
    } 
}