如何对例外进行单元测试? [英] How to do unit test for Exceptions?

查看:122
本文介绍了如何对例外进行单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

As you know, exception is thrown at the condition of abnormal scenarios. So how to analog these exceptions? I feel it is challenge. For such code snippets:

public String getServerName() {
    try {

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

有没有人有好主意?

推荐答案

其他答案解决了如何编写单元测试以检查是否抛出异常的一般问题。但我认为你的问题实际上是询问如何让代码首先抛出异常。

Other answers have addressed the general problem of how to write a unit test that checks that an exception is thrown. But I think your question is really asking about how to get the code to throw the exception in the first place.

以你的代码为例。要使 getServerName()在一个简单的单元测试的上下文中内部抛出一个异常是非常困难的。问题是,为了发生异常,代码(通常)需要在网络被破坏的机器上运行。安排在单元测试中发生这种情况可能是不可能的......在运行测试之前,你需要故意错误配置机器。

Take your code as an example. It would be very hard to cause your getServerName() to internally throw an exception in the context of a simple unit test. The problem is that in order for the exception to happen, the code (typically) needs to be run on a machine whose networking is broken. Arranging for that to happen in a unit test is probably impossible ... you'd need to deliberately misconfigure the machine before running the test.

那么答案是什么?


  1. 在某些情况下,简单的答案就是采取务实的决定,而不是进行全面的测试覆盖。你的方法就是一个很好的例子。从代码检查中应该清楚该方法实际上做了什么。测试它不会证明什么(除了见 ** )。您所做的只是提高测试次数和测试覆盖率,这两者都不应该是项目目标

  1. In some cases, the simple answer is just to take the pragmatic decision and not go for total test coverage. Your method is a good example. It should be clear from code inspection what the method actually does. Testing it is not going to prove anything (except see below **). All you are doing is improve your test counts and test coverage numbers, neither of which should be project goals.

在其他情况下,分离出生成异常的低级代码并将其作为一个单独的类可能是明智的。然后,要测试异常的更高级代码的处理,可以使用将抛出所需异常的mock类替换该类。

In other cases, it may be sensible to separate out the low-level code where the exception is being generated and make it a separate class. Then, to test the higher level code's handling of the exception, you can replace the class with a mock class that will throw the desired exceptions.

这是治疗的例子。 (这有点人为......)

Here is your example given this "treatment". (This is a bit contrived ... )

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

现在进行单元测试,你创建 ILocalDetails 接口的模拟实现,其 getLocalHost()方法在适当的情况下抛出你想要的异常条件。然后为 SomeClass.getServerName()创建一个单元文本,安排 SomeClass 的实例使用你的实例模拟类而不是正常类。 (最后一点可以使用模拟框架,通过为 local 属性公开 setter 或使用反射API。)

Now to unit test this, you create a "mock" implementation of the ILocalDetails interface whose getLocalHost() method throws the exception you want under the appropriate conditions. Then you create a unit text for SomeClass.getServerName(), arranging that the instance of SomeClass uses an instance of your "mock" class instead of the normal one. (The last bit could be done using a mocking framework, by exposing a setter for the local attribute or by using the reflection APIs.)

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

Obviously, you would need to modify your code to make it testable like this. And there are limits to what you can do ... for example, you now cannot create a unit test to make the real LocalDetails.getLocalHost() method to throw an exception. You need to make a case-by-case judgement as to whether it is worth the effort of doing this; i.e. does the benefit of the unit test outweigh the work (and extra code complexity) of making the class testable in this way. (The fact that there is a static method at the bottom of this is a large part of the problem.)

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

** There is a hypothetical point to this kind of testing. In your example, the fact that the original code catches an exception and returns an empty string could be a bug ... depending on how the method's API is specified ... and a hypothetical unit test would pick it up. However, in this case, the bug is so blatant that you would spot it while writing the unit test! And assuming that you fix bugs as you find them, the unit test becomes somewhat redundant. (You wouldn't expect someone to re-instate this particular bug ...)

这篇关于如何对例外进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆