如您所知,在异常情况下会抛出异常.那么如何模拟这些异常呢?我觉得这是挑战.对于此类代码段:
public String getServerName() {
try {
InetAddress addr = InetAddress.getLocalHost();
String hostname = addr.getHostName();
return hostname;
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
Run Code Online (Sandbox Code Playgroud)
有人有好主意吗?
Uri*_*Uri 67
你可以告诉junit正确的行为是获得异常.
在JUnit 4中,它类似于:
@Test(expected = MyExceptionClass.class)
public void functionUnderTest() {
…
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*n C 34
其他答案解决了如何编写单元测试以检查是否抛出异常的一般问题.但我认为你的问题实际上是在询问如何让代码首先抛出异常.
以您的代码为例.getServerName()
在简单的单元测试的上下文中导致内部抛出异常将非常困难.问题是,为了发生异常,代码(通常)需要在网络被破坏的机器上运行.安排在单元测试中发生这种情况可能是不可能的......在运行测试之前,您需要故意错误配置机器.
所以答案是什么?
在某些情况下,简单的答案只是采取务实的决定,而不是进行全面的测试覆盖.你的方法就是一个很好的例子.从代码检查中应该清楚该方法实际上做了什么.测试它不会证明什么(除了见下文**
).您所做的只是改善您的测试计数和测试覆盖率,这两者都不应该是项目目标.
在其他情况下,分离出生成异常的低级代码并将其作为单独的类可能是明智的.然后,要测试更高级代码对异常的处理,可以使用将抛出所需异常的mock类替换该类.
这是"治疗"的例子.(这有点人为......)
public interface ILocalDetails {
InetAddress getLocalHost() throws UnknownHostException;
...
}
Run Code Online (Sandbox Code Playgroud)
public class LocalDetails implements ILocalDetails {
public InetAddress getLocalHost() throws UnknownHostException {
return InetAddress.getLocalHost();
}
}
Run Code Online (Sandbox Code Playgroud)
public class SomeClass {
private ILocalDetails local = new LocalDetails(); // or something ...
...
public String getServerName() {
try {
InetAddress addr = local.getLocalHost();
return addr.getHostName();
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在对单元测试,你创建一个ILocalDetails
接口的"模拟"实现,其getLocalHost()
方法在适当的条件下抛出你想要的异常.然后你创建一个单元文本SomeClass.getServerName()
,安排实例SomeClass
使用你的"模拟"类的实例而不是正常的实例.(最后位可以使用一个模拟框架来完成,通过暴露一setter
对local
属性或通过使用反射的API.)
显然,您需要修改代码以使其像这样可测试.你可以做什么是有限的...例如,你现在不能创建一个单元测试来使真正的LocalDetails.getLocalHost()
方法抛出异常.你需要逐案判断是否值得这样做的努力; 即,单元测试的好处是否超过了以这种方式使类可测试的工作(以及额外的代码复杂性).(事实上,static
在这个问题的底部有一个方法是问题的很大一部分.)
**
这里是一个假设点这种测试.在您的示例中,原始代码捕获异常并返回空字符串的事实可能是一个错误...取决于方法的API如何指定...并且假设单元测试将提取它.但是,在这种情况下,bug是如此明显,以至于你在编写单元测试时会发现它!假设您在找到错误时修复了错误,则单元测试变得有些多余.(你不会指望有人重新设置这个特定的bug ...)
Mat*_*att 14
好的,这里有一些可能的答案.
对异常进行测试很容易
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@Test
public void TestForException() {
try {
doSomething();
fail();
} catch (Exception e) {
assertThat(e.getMessage(), is("Something bad happened"));
}
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用异常注释来指出您希望出现异常.
现在,至于你的具体例子,当你无法与对象交互时,测试你在方法中创建的东西,无论是通过新的还是静态的,都很棘手.您通常需要封装该特定生成器,然后使用一些模拟来覆盖行为以生成您期望的异常.
由于这个问题在社区维基中,我将添加一个新的完整性:您可以ExpectedException
在JUnit 4中使用
@Rule
public ExpectedException thrown= ExpectedException.none();
@Test
public void TestForException(){
thrown.expect(SomeException.class);
DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
将ExpectedException
使得抛出的异常提供给所有的测试方法.
也可以测试特定的错误消息:
thrown.expectMessage("Error string");
Run Code Online (Sandbox Code Playgroud)
或使用匹配器
thrown.expectMessage(startsWith("Specific start"));
Run Code Online (Sandbox Code Playgroud)
这比更短,更方便
public void TestForException(){
try{
DoSomething();
Fail();
}catch(Exception e) {
Assert.That(e.msg, Is("Bad thing happened"))
}
}
Run Code Online (Sandbox Code Playgroud)
因为如果你忘了失败,测试可能会导致误报.
许多单元测试框架允许您的测试将异常作为测试的一部分.例如,JUnit 允许这样做.
@Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
int[] intArray = new int[10];
int i = intArray[20]; // Should throw IndexOutOfBoundsException
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
65743 次 |
最近记录: |