如何对异常进行单元测试?

2022-09-01 06:17:41

如您所知,异常情况在情况异常时会引发异常。那么如何模拟这些异常呢?我觉得这是挑战。对于此类代码片段:

public String getServerName() {
    try {

        InetAddress addr = InetAddress.getLocalHost();
        String hostname = addr.getHostName();
        return hostname;
    }
    catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

有人有好主意吗?


答案 1

你可以告诉 junit 正确的行为是获取异常。

在 JUnit 4 中,它如下所示:

@Test(expected = MyExceptionClass.class) 
public void functionUnderTest() {
    …
}

答案 2

其他答案已经解决了如何编写检查是否引发异常的单元测试的一般问题。但我认为你的问题实际上是在问如何首先获取代码以引发异常。

以您的代码为例。在简单单元测试的上下文中,很难导致您在内部引发异常。问题在于,为了发生异常,代码(通常)需要在网络中断的计算机上运行。在单元测试中安排这种情况可能是不可能的......在运行测试之前,您需要故意错误配置计算机。getServerName()

那么答案是什么呢?

  1. 在某些情况下,简单的答案只是做出务实的决定,而不是追求全面的测试覆盖率。您的方法就是一个很好的例子。从代码检查中应该可以清楚地看出该方法的实际作用。测试它不会证明任何东西(除了见下文)。您所要做的就是提高测试计数和测试覆盖率,这两者都不应该是项目目标**

  2. 在其他情况下,明智的做法是分离出生成异常的低级代码,并使其成为一个单独的类。然后,若要测试更高级别代码对异常的处理,可以将该类替换为将引发所需异常的模拟类。

这是你给出的这个“治疗”的例子。(这有点人为的...

public interface ILocalDetails {
    InetAddress getLocalHost() throws UnknownHostException;
    ...
}

public class LocalDetails implements ILocalDetails {
    public InetAddress getLocalHost() throws UnknownHostException {
        return InetAddress.getLocalHost();
    }
}

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

现在,为了对此进行单元测试,您可以创建接口的“模拟”实现,其方法在适当的条件下引发所需的异常。然后,为 创建一个单元文本,安排 的实例使用 “mock” 类的实例,而不是普通类的实例。(最后一位可以使用模拟框架、通过公开属性的 a 或使用反射 API 来完成。ILocalDetailsgetLocalHost()SomeClass.getServerName()SomeClasssetterlocal

显然,您需要修改代码以使其像这样可测试。而且你能做的是有限的...例如,您现在无法创建单元测试来使真正的方法引发异常。您需要逐案判断是否值得这样做;也就是说,单元测试的好处是否超过了以这种方式使类可测试的工作(和额外的代码复杂性)。(事实上,底部有一种方法,这是问题的很大一部分。LocalDetails.getLocalHost()static


**这种测试一个假设点。在您的示例中,原始代码捕获异常并返回空字符串的事实可能是一个错误...取决于如何指定方法的 API...一个假设的单元测试会把它捡起来。但是,在这种情况下,该错误是如此明显,以至于您会在编写单元测试时发现它!假设你在发现错误时修复它们,单元测试变得有些多余。(你不会期望有人恢复这个特定的错误...


推荐