业务方法中的错误检查 a.k.a 进行防御性编程

Error checking in business methods a.k.a doing defensive programming

我开始向大型 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;
}

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

We are not error checking everything. If you parameter is rubbish you will know fast!

另一半说:

We must add ifs to the id and then to the o and if any of them are null the null is what we return.

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

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

虽然这在某种程度上是基于意见的,但如果给定 null 作为参数,很少有人会说 return null 是正确的。如果我要添加任何东西,它最多是一个IllegalArgumentException(甚至NPE)当传入null时。

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

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

您可以使用 Null Object Pattern.

或者抛出异常、非法参数或 entitynotexsits spring。

如果必须 return null,至少将其包装在 optional or use guava.

一如既往,这取决于 :)

如果您正在编写库代码(在其他地方或什至其他地方共享和使用的代码),那么您应该真正致力于以一致的方式处理所有可想到的输入值。使用记录良好的异常而不是 returning null 对于库代码来说当然更可取。

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

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