【问题标题】:Error checking in business methods a.k.a doing defensive programming业务方法中的错误检查,也就是进行防御性编程
【发布时间】:2015-08-17 12:08:01
【问题描述】:

我开始向大型 Java 代码库添加测试。我经常在我正在测试的会话 bean 中看到以下内容:

public OrderDTO getOrderDTO(Long id) {
    Order o = (Order)entityManager.find(Order.class, id);
    OrderDTO dto = new OrderDTO(o.getId(), o.getCurrency());
    return dto;
}

编写单元测试来破坏此代码很容易(发送空或不存在的 id)。当我这样做时,团队的一半开发人员说:

我们不会对所有内容进行错误检查。如果你的参数是垃圾,你很快就会知道!

另一半说:

我们必须将 ifs 添加到 id 和 o 中,如果其中任何一个为 null,则返回 null。

单元测试的目的不就是准确地找出这些问题吗? (是的,我在征求意见!)

是的,从 Long 切换到 long 会删除一个 if。

【问题讨论】:

    标签: java unit-testing junit stateless-session-bean defensive-programming


    【解决方案1】:

    虽然这有点基于意见,但很少有人会说如果将 null 作为参数返回 null 是正确的。如果我要添加任何内容,则在传入 null 时最多是 IllegalArgumentException(甚至是 NPE)。

    可以创建一个测试来检查方法是否以一致的方式失败,但它实际上是在测试 JPA 提供者的行为,而不是您的代码。

    【讨论】:

    • 所以你会添加一个 *Exception 并保持代码不变?我的看法是在方法参数中将 Long 更改为 long 并保持代码不变。
    • @user1329339 将类型从 Long 更改为 long 并没有那么重要,null 只是解析为零。
    • @user1329339 我不会添加任何东西。我会进行集成测试,以验证无法执行会导致 null 传递给此方法的操作。
    • @Kayaman 感谢您的回复。我添加了测试,检查传递 null 时是否引发错误,我将添加您建议的测试。
    • @user1329339 空值将返回与 id 0 关联的记录 - 这可能对您有用,但也可能不适用。
    【解决方案2】:

    应该避免返回空值,它们是万恶之源。

    您可以使用Null Object Pattern

    或者抛出异常、非法参数或实体注解。

    如果必须返回 null,至少将其包装在 optional 中或使用 guava

    【讨论】:

      【解决方案3】:

      和往常一样,这取决于:)

      如果您正在编写库代码(在其他地方甚至由其他人共享和使用的代码),那么您应该真正致力于以一致的方式处理所有可想到的输入值。对于库代码来说,使用有据可查的异常而不是返回 null 肯定是更可取的。

      另一方面,有本地代码。 我可以看到该方法是public,但这并不能消除它仅用于代码库的一个孤立部分的可能性。
      在这种情况下,您不会使用有关参数的假设以及调用者期望的回报。您使用已定义的调用。您可以控制发送的内容以及调用者如何处理返回值。因此,如果您知道调用者从不发送空值,则可以不进行空值检查。如果这样可以简化您的整体程序结构,也可以返回 null。

      ps:如果entityManager.find(..) 失败,最困扰我的是未处理的 NPE :)

      【讨论】:

        猜你喜欢
        • 2018-07-29
        • 2015-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多