Java断言,与单元测试和异常相比

Java断言,与单元测试和异常相比,java,unit-testing,exception-handling,assert,Java,Unit Testing,Exception Handling,Assert,这是我的一个高层次的一般性问题: 为什么要使用断言而不是单元测试和异常处理? 为了澄清我的困惑并澄清我的担忧,我将谈谈我对Java断言的了解以及我与这一问题相关的背景 因此,首先,在本周之前,我甚至不知道Java框架的断言,也不知道它们的功能,所以我绝对承认我可能不了解全部情况。话虽如此,我在web开发、数据和API开发方面已经有近十年的专业经验了,所以我并不完全幼稚 从我所读到的以及我所进行的讨论来看,断言通常在开发过程中使用,(几乎)总是在生产过程中关闭,并将检查后条件和类不变值;它们可以也

这是我的一个高层次的一般性问题:

为什么要使用断言而不是单元测试和异常处理?

为了澄清我的困惑并澄清我的担忧,我将谈谈我对Java断言的了解以及我与这一问题相关的背景

因此,首先,在本周之前,我甚至不知道Java框架的断言,也不知道它们的功能,所以我绝对承认我可能不了解全部情况。话虽如此,我在web开发、数据和API开发方面已经有近十年的专业经验了,所以我并不完全幼稚

从我所读到的以及我所进行的讨论来看,断言通常在开发过程中使用,(几乎)总是在生产过程中关闭,并将检查后条件和类不变值;它们可以也可以用于其他用途,但这两种用途似乎是它们在当代的主要用途。它们构建在Java异常之上,是
Error
的子类型,并且在违反时抛出。禁用时,它们不会增加运行时开销

然而,对我来说,它们似乎是多余的,特别是在考虑良好的异常处理技术和良好的单元测试实践时。我看不到任何情况下断言会提醒程序员错误或异常处理或单元测试不会出现的问题

按照这条思路,我觉得他们似乎在制造代码混乱。如果它们不打算在生产环境中运行并充当开发辅助工具,那么它们在生产代码中的存在就有点反模式:您有单独的测试源文件夹和测试资源,您编写可测试代码,而不是严格用于测试的代码。每当我发现自己编写代码只是为了进行测试时,这就提醒了我糟糕的设计,我会后退一步,重新设计我正在做的事情,以便我的代码是可测试的。在我看来,这是一个被违反的范例。只要存在断言,就可以用try/catch块、if/then/else替换它,并抛出相应的异常,或者用一组单元测试替换它——至少在我看来是这样。在生产代码中包含不会在生产过程中运行的断言是令人困惑的。它还分散了代码的目的和代码的作用。我发现,一个测试如果能够评估与断言相同的条件,那么它的可读性会大大提高,因为它包含在一个测试中,可以为该场景命名和记录

其他人能为这一思路增添洞察力吗?也许你同意——举例说明原因或阐述我的推理。再说一次,也许你认为我错了——说明原因并举例支持你的推理,或者为我看待事物的方式提供反驳

谢谢大家


我咨询过的资源,供您参考:


使用断言,应该涵盖被认为不可能发生的情况。当不可能的事情发生时,最好是大声说出来,然后继续,并在后面的某个点提供不正确的结果或不相关的异常。单元测试并不是一种真正的替代方法,因为您不能使用它们来证明某些条件不可能发生

一个典型的用法是
开关
语句。如果您确信所有可能的状态都包含在
case
子句中,则可以将
default
块保留为空,并希望您是正确的(当周围的代码发生更改时,您仍然是正确的),或者将断言放在那里,以便在出现错误时通知您


您是决定使用Java的
assert
语句(如您所说可以关闭),还是直接抛出
AssertionError
(这是无法关闭的),完全取决于您。

使用断言时,应该涵盖被认为不可能发生的情况。当不可能的事情发生时,最好是大声说出来,然后继续,并在后面的某个点提供不正确的结果或不相关的异常。单元测试并不是一种真正的替代方法,因为您不能使用它们来证明某些条件不可能发生

一个典型的用法是
开关
语句。如果您确信所有可能的状态都包含在
case
子句中,则可以将
default
块保留为空,并希望您是正确的(当周围的代码发生更改时,您仍然是正确的),或者将断言放在那里,以便在出现错误时通知您


您是决定使用Java的
assert
语句(如您所说可以关闭),还是直接抛出
AssertionError
(这是无法关闭的),完全取决于您。

这个主题是关于观点的,所以我只添加一些关于这个主题的想法。这些并不包括所有方面,但可以补充其他人的意见

有时我使用断言只是为了表示我在编写代码时做了一些假设。简单的例子:我调用方法来获取值,通常可以是“代码> null <代码>,例如按名称查找用户,但在这种特殊情况下,这是不能发生的,因为我正处于注册的中间。因此,我跳过了代码中的“空检查”,但我想明确告诉谁以后会阅读我的代码(可能是一个月后的我:),我已经考虑过这个选项

User user = findUser(userId);
assert user != null : "we are in the middle of registration"
user.confirmEmail();

显然,我可以使用简单的注释来实现这一点,但当涉及到代码的混乱时,情况不会更糟

第二个用例是,正如您已经提到的,检查不变量。“学校示例”是指您正在实施合并排序的情况,在合并阶段,算法期望您要合并的两个子阵列都已排序(根据先前的ste)