Junit4: 取消弃用 ExpectedException 规则

创建于 2019-05-05  ·  22评论  ·  资料来源: junit-team/junit4

在将 Spring Framework 升级到 JUnit 4.13 beta 3 后,我注意到org.junit.rules.ExpectedException现在是@Deprecated ,并且这种更改在像这样的大型代码库中产生了很多警告。

由于 4.13 是 4.x 系列中的最后一个预期版本,我认为弃用这种常用和支持的功能没有意义。

如果您继续弃用,我担心它只会无缘无故地惹恼成千上万(数百万?)的开发人员。

rules

最有用的评论

@daicoden

我很确定assertThrows返回 throwable,因此您可以捕获它并像对任何其他对象一样进行断言:

StatusRuntimeException thrown = assertThrows(StatusRuntimeException.class, () -> {
   GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());
});

assertEquals(Status.INVALID_ARGUMENT, thrown.getStatus());

所有22条评论

我认为弃用警告是表明有更好的东西可用的好方法,所以警告不是没有充分的理由。 ExpectedException很容易被误用,但在很多地方仍然推荐使用。

问题是我们的用户收到这些弃用警告有多大问题。 在我的公司中,弃用警告不会在构建时出现(仅在查看代码时)。

我认为 Sam 说的有道理。 我见过许多禁止所有(新)编译器警告的构建。 此类项目必须通过所有使用ExpectedException的测试类并添加SuppressWarnings注释。

@stefanbirkner WDYT?

让客户抑制警告似乎是合理的。 他们还可以抑制所有弃用警告; 将弃用警告视为错误使得不可能弃用任何东西。

弃用是我们向人们表明旧 API 有问题并且有更好的 API 可用的最佳方式。

我了解开发人员可以在 IDE 中本地抑制警告; 但是,我不同意弃用 JUnit 4.x 的(计划中的)最终版本中的核心功能是个好主意。

恕我直言,在任何框架的最终版本中弃用核心功能并不是一个好主意,尤其是像 JUnit 4 这样广泛使用的框架。

作为一个具体的例子,在核心 Spring Framework 测试套件中,我们现在有数千个使用ExpectedException规则的弃用警告。

我们唯一的选择是:

  1. 在每个使用ExpectedException测试类中抑制弃用警告。
  2. 在使用ExpectedException的每个测试类中迁移它。
  3. 没做什么。

如果我们采用#1,我们可能可以通过一些脚本来实现这一点,该脚本在类级别抑制警告,但这会抑制我们可能想要/需要了解而不是忽略的其他 API 的弃用警告。 否则,我们必须手动检查每个测试类并弃用ExpectedException API 的每次使用,这包括在所有受影响的测试方法中与规则实例的每一次交互。

如果我们采用#2,这是一项重大任务,手动完成可能需要几天时间。 部分自动化可能是可能的,但对自动化(脚本等)的投资本身可能相当广泛。

如果我们采用#3,那么我们就会有不必要的(从我们的角度来看)弃用警告,这些警告使我们对实际关心的弃用警告的看法变得模糊,这会导致我们想要避免的破窗效应。

执行 #2 将简化未来向 JUnit 5 的迁移。

执行 #2 将简化未来向 JUnit 5 的迁移。

当然。 这将使迁移到 JUnit Jupiter 或 AssertJ 可能更容易; 然而,并不是每个人都想要或需要迁移现有的测试套件。

因此,我不认为这是一个有效的论点。

我不确定为什么这可能是最后一个 JUnit 4.x 版本与我们是否弃用有关。 JUnit 很少删除 _any_ API,因此弃用并不表示 API 即将消失。 这表明 API 可能不受支持和/或存在更好的 API。 在这种情况下两者都是正确的(我们拒绝了对该规则的提议更改,因为我们认为让人们使用assertThrows()更好)

我建议 Spring 从ExpectedException慢慢迁移。 几天的工作分散在几个月内,以获得更安全、更易于理解的测试似乎是一种胜利。 好处是其他不太熟悉 JUnit 最近变化的人会知道避免ExpectedException

ErrorProne 对此进行了检查,该检查将提供推荐的修复程序,因此我认为解决此问题不需要几天时间。

TL;DR 我赞成弃用 ExpectedException。

@kcooney已经说过,JUnit 4 中的弃用并不意味着我们将删除某些内容,因为 JUnit 4 的设计决策是为了避免破坏性更改。 因此,这是否是最后一个 4.x 版本并不重要。

我认为弃用是有帮助的,因为它告诉人们有一种更好的检查异常的方法。 在过去的 10 年里,我为几家公司工作过,总是有人惊讶于有比@Test(expected=ABeautifulException.class更好的东西。 弃用对他们来说很有价值,因为当他们看到在 IDE 中被删除的代码时,他们通常会查看一下。

弃用警告可能很烦人,因为没有必要修复这些警告。 这源于 JUnit 4 使用弃用的方式。 因此,我认为除了不弃用 ExpectedException(最后根本不使用弃用)之外,没有解决此问题的方法。

最后但并非最不重要的是,有些公司的构建会在出现弃用警告的情况下中断,因此他们无法轻松升级到 JUnit 4.13。 我不确定这些公司中有多少存在,这些公司 a) 拥有此构建策略并且 b) 想要升级到 JUnit 4.13。

@sdeleuze@mp911de@rweisleder您投票支持恢复弃用。 如果您告诉我们您希望它不被弃用的原因,那将会很有帮助。

只是为了提供更多信息,将 Spring Framework 的代码库从 JUnit 的ExpectedException迁移到 AssertJ 的assertThatExceptionOfType大约需要 1.5 天。

一个可能有帮助的小建议是考虑只弃用ExpectedException.none()方法而不是整个类。 这仍然会给人们带来警告,但它会更容易孤立压制。

JUnit 的ExpectedException在执行比@Test(expected = …)更广泛的异常断言的测试中用作原始类型。 这些通常是依赖于 Hamcrest 或内置断言而不是 AssertJ 之类的测试。

拥有 JUnit 4.13 是主动维护发生的信号。 保留在 JUnit 4.x API 上的代码库可能不会很快迁移到 JUnit 5 API,而是保留 API 并有可能迁移到 Vintage 引擎。 尽管代码可能仍在工作,但突然弃用的类会生成新的警告和额外的工作以迁移到不同的断言实用程序。

我已经观察过几次改进的 API 的弃用和引入。 在大多数情况下,弃用有助于维护人员而不是实际用户。 在用户方面,这主要产生了努力而没有任何好处。

一个可能有帮助的小建议是考虑只弃用ExpectedException.none()方法而不是整个类。 这仍然会给人们带来警告,但它会更容易孤立压制。

如果 JUnit 4 团队决定不反对ExpectedException规则,我认为这将是一个很好的妥协。

我想知道@Test(expected = ...)是否也应该被弃用,因为我们现在有assertThrows 。 或者至少应该从属性的 Javadoc 中删除对ExpectedException的引用。

我想知道@Test(expected = ...)是否也应该被弃用,因为我们现在有assertThrows 。 或者至少应该从属性的 Javadoc 中删除对ExpectedException的引用。

是的, expected在属性org.junit.Test应该有可能被弃用。 无论如何,应该更新org.junit.Testexpected属性的类级 Javadoc 以推荐使用assertThrows

我会赞成只弃用ExpectedException.none()

我相信使用弃用来宣传新功能是一种严厉的方法,它会损害对 JUnit 开发过程的信任并阻碍 4.13 版的采用。

当新旧功能共存而没有被弃用时,应该有一个版本重叠。 正如其他人指出的那样,对于许多保持高代码质量的项目来说,依赖已弃用的方法是不行的。 这意味着 JUnit 升级应该与迁移整个代码库的更改在同一提交中。

我认为,不推荐使用某个功能并在同一版本中添加替换功能的唯一情况是该功能从根本上被破坏并应立即迁移。 我不认为ExpectedException从根本上被打破。

我经常会检查更新的依赖项,以了解即将发生的变化以及如何准备我的代码。 那么,如何让我的代码为 JUnit 4.13 迁移做好准备? 我知道ExpectedException将被弃用,但我还没有一个好的替代品。 我需要实现我自己的代码来捕获和检查异常以避免完全混乱。

仅仅因为 4.13 计划成为最终的 4.x 版本,这并不是放弃理智的软件开发实践的好理由。 事实上,4.13 可以在没有ExpectedException弃用的情况下发布,而 4.14 可以在第二天发布弃用。 这将传达信息,同时让开发人员在没有过度压力的情况下进行迁移有一点喘息的时间。

当新旧功能共存而没有被弃用时,应该有一个版本重叠。

为什么? 弃用的目的是让人们了解新的,在我们看来更好的 API。

我也同意我们应该只弃用ExpectedException.none()以减少侵入性。

@stefanbirkner你还好吗?

@marcphilipp当我更新我的代码时,我希望事情不会被弃用,除非我做错了什么。 弃用一个功能并同时提供替代品太麻烦了。 相反,4.13 发行说明应该说ExpectedException将在下一个版本中被弃用并建议替换。 这样,我将有一种方法可以逐步迁移我的代码,而不必同时允许弃用。 这只是对多年来一直使用 JUnit 4.12 并且不想进行大改动的用户的基本礼貌。

恕我直言,弃用警告 _is_ 的重点是让您有时间将代码迁移到替换版本。 如果您需要解决弃用警告,您可以创建自己的临时工厂方法,委托给ExpectedException.none()

好的,PR 在一定程度上缓解了这个问题,这绝对是朝着正确方向迈出的一步。 谢谢你这样做!

不是建议用户实现工厂方法,代码可以提供自己的非弃用方法(可能none带有额外的参数)。

我仍然不明白反对为用户提供过渡版本的阻力。 在实施不兼容的更改时,制作一个允许转换而不以任何方式强制转换的版本是很常见的。

如果没有过渡版本,用户会尝试 4.13,看到大量警告并返回 4.12。

使用过渡版本,用户会尝试 4.14,看到大量警告,尝试 4.13,看到没有警告,使用它。 有些人会很快更新到 4.14,其他人会很乐意留在 4.13,除非他们有充分的理由更新。 无论哪种方式都应该没问题。

我也不明白为什么在 JUnit 4 中应该发生这种弃用。我正在使用junit-vintage-engine迁移到 JUnit 5 以暂时支持这两个版本。 但这引入了 JUnit 4.13,出于某种原因,它决定弃用可能是其最新版本之一的东西(已支持多年)是个好主意。

除了指出替代方案之外,似乎也没有理由不赞成使用 - 这可以通过至少提供替代方案(使构造函数公开,或提供另一个静态方法 - 消息传达)来实现。

现在的ExpectedException代码将继续工作(并且即使在以后的版本中也将继续工作),因为它只是使用以(当时)方便的方式提供的 JUnit 的基本功能。

什么是断言有关异常的属性的替代品......

旧代码:

thrown.expect(StatusRuntimeException.class);
thrown.expect(its(StatusRuntimeException::getStatus, toBe(Status.INVALID_ARGUMENT)));
GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());

似乎 assertThrows 缺少匹配器版本以允许完全弃用预期的异常......我知道为时已晚但没有其他人有这个问题?

@daicoden

我很确定assertThrows返回 throwable,因此您可以捕获它并像对任何其他对象一样进行断言:

StatusRuntimeException thrown = assertThrows(StatusRuntimeException.class, () -> {
   GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());
});

assertEquals(Status.INVALID_ARGUMENT, thrown.getStatus());
此页面是否有帮助?
0 / 5 - 0 等级