围绕异常单元测试区域的正确方法是什么

时间:2010-05-20 11:23:17

标签: unit-testing exception

查看我们的单元测试的代码覆盖率,我们非常高。但最后几个%是棘手的,因为他们中的很多人正在捕捉像数据库异常这样的东西 - 在正常情况下这些都不会发生。例如,代码可以防止字段太长等,因此唯一可能的数据库异常是,如果数据库被破坏/关闭,或者模式在我们的脚下被更改。

那么模拟对象以便抛出异常的唯一方法是什么?这似乎有点无意义。也许最好不接受100%的代码覆盖率?

谢谢, 丹

3 个答案:

答案 0 :(得分:1)

指定100%覆盖率目标时的常见做法是通过测试覆盖尽可能多的代码,并通过代码审查覆盖剩余的几个百分比。

答案 1 :(得分:1)

通常在遇到低级异常(如Java中的IOException或SQLException)时,我将它们包装到一个扩展RuntimeException的异常中。我觉得测试这种行为非常重要,因为否则会有意外吞下异常的可能性。

所以我建议测试它们,如果你在抛出低级异常时真的做了什么。

编辑:添加了示例。

public void store(User user) {
    try {
        userDao.store(user);
    } catch (IOException e) {
        // Logging, perhaps some logic.
        throw new ServiceException(e);
    }
}

@Test(expected = ServiceException.class)
public void Store_Fail() {
    UserDao userDaoMock = createMock(UserDao.class);
    User user = // Create test user.
    userDaoMock.store(user);
    replay(userDaoMock);
    userService.store(user);
    verify(userDaoMock);
}

这里测试的内容不多,但是如果逻辑需要抛出ServiceException,为什么不测试呢?

答案 2 :(得分:0)

那么模拟对象以便抛出异常的唯一方法是什么?

我相信这将是最简单的方法,但你也可以做一个存根(也就是一个扩展真实对象的对象,并强迫每次都抛出异常)。或者您可以使用AOP,但我认为使用像easymockjmock这样的库将是最简单的方法。

这似乎有点无意义。也许最好不接受100%的代码覆盖率?

每当我谈论这个话题时,我都希望改变人们的思维方式而不是担心一定比例的覆盖率,而是将百分比作为工具来使你成为更好的开发者。另一种方式是100%覆盖率或50%覆盖率并不一定意味着你的代码写得很好甚至工作,但是在开发代码时使用代码覆盖率作为关键指标,如果你一直在编写测试等等...一个好主意。

我个人对你的问题的看法是,如果它是你的应用程序正在做的逻辑,那么值得测试。因此,如果您正在捕获异常并从该方法重新调整false,那么您应该对此进行测试。如果您正在捕获异常并将其包装在另一个异常中,那么您应该测试它。如果您正在捕捉异常并且什么都不做,那么这应该是需要修复的代码气味,因为这会导致各种无法控制的副作用。

至于100%是不是发怒,我会说是的,这是不值得的。你应该为自己找到一个很好的舒适度(可能是80%,也许是90%)并坚持下去。但我不会基于测试的类型(比如测试异常逻辑),它应该只基于总覆盖率,并且被视为在提交代码时没有编写测试的指示器。