7

我目前正在针对我的代码重新使用来自另一个项目的 JUnit 4 测试。作为我的自动化 Ant 构建的一部分,我直接从另一个项目的存储库中获取它们。这很棒,因为它确保我的代码在最新版本的测试中保持绿色。

但是,有一部分测试是我从没想过会传递给我的代码的。但是,如果我开始向这些测试添加@Ignore 注释,我将不得不维护我自己的测试实现的单独副本,我真的不想这样做。

有没有办法在不修改测试源的情况下排除单个测试?这是我到目前为止所看到的:

  • 据我所知,Ant JUnit 任务只允许您排除整个测试类,而不是单个测试方法——所以这对我没有好处,我需要方法粒度。

  • 我考虑将使用反射动态查找和添加所有原始测试的 TestSuite 放在一起,然后添加代码以显式删除我不想运行的测试。但是当我注意到TestSuite API没有提供删除测试的方法时,我放弃了这个想法。

  • 我可以创建自己的测试类来扩展原始测试类,覆盖我不想运行的特定测试,并用@Ignore 注释它们。然后我在我的子类上运行 JUnit。这里的缺点是,如果将新的 Test 类添加到原始项目中,我不会自动选择它们。当新的 Test 类被添加到原始项目时,我将不得不监视它们。到目前为止,这是我最好的选择,但感觉并不理想。

  • 我能想到的唯一其他选择是无论如何都运行糟糕的测试并忽略失败。但是,这些测试需要一段时间才能运行(并且失败!)所以我宁愿根本不运行它们。此外,我看不到告诉 Ant 任务忽略特定测试方法上的失败的方法(再次 - 我看到了如何为单个 Test 类而不是方法做到这一点)。

4

7 回答 7

4

如果您根本无法触及原始测试,那么您将面临一些严重的限制。您的压倒一切听起来像是最好的选择,但有一些变化:

构建专门排除超类的 Ant 测试,以便运行您不知道的其他类。

您可以使用 @Rule 注释(JUnit 4.7 的新功能)来了解正在运行的测试并中止它(通过返回一个空的 Statement 实现)而不是覆盖特定方法,从而让您更灵活地了解是否要避免测试. 此方法的唯一问题是您无法使用此方法停止 @Before 方法运行,这可能会很慢。如果这是一个问题(并且您真的无法触及测试),那么覆盖方法中的 @Ignore 是我唯一能想到的。

但是,如果您可以触摸这些测试,则会打开一些其他选项:

您可以通过在类上指定 @RunWith 标记来使用自定义运行器运行它们。该运行程序只会将执行传递给该项目中的标准运行程序(JUnit4.class),但在您的项目中(通过系统属性或其他机制)将检查测试名称而不运行测试。这样做的好处是侵入性最小,但最难实现(跑步者是毛茸茸的野兽,@Rule 的既定目标之一是消除大部分制作它们的需要)。

另一种方法是在测试中创建一个假设语句,该语句将检查一些配置设置,如果该测试应该运行,这些设置将是正确的。这实际上将涉及直接注入测试,这很可能是任何远程标记为“单独项目”的交易破坏者。

于 2009-09-02T17:19:13.773 回答
3

它现在对你没有帮助,但 TestNG 支持这种能力。

于 2009-09-02T17:51:39.543 回答
2

好的,这是一个相当重量级的解决方案,但如果这听起来很荒谬,请不要向我扔东西。

Junit4 的核心是org.junit.runner.Runner类,以及它的各种子类,最重要的是org.junit.runners.Suite. 这些运行程序使用@Test 和@Ignore 之类的东西确定给定测试类的测试内容。

创建运行器的自定义实现非常容易,通常您可以通过@RunWith在测试类上使用注释来连接它们,但显然这不是您的选择。

但是,理论上您可以编写自己的 Ant 任务,也许基于标准的 Ant Junit 任务,它采用您的自定义测试运行器并直接使用它,依次将每个测试类传递给它。您的运行器实现可以使用一个外部配置文件,该文件指定要忽略的测试方法。

这将是相当多的工作,并且您必须花时间在史前 Ant Junit 代码库中挖掘以了解它是如何工作的。然而,时间上的投资可能是值得的。

遗憾的是 Junit Ant 任务没有提供指定测试 Runner 的机制,这将是理想的。

于 2009-09-02T17:20:07.640 回答
1

我能想到的一种可能性是使用字节码修改来实现你想要的约束。您可以在单独的文件中保留要忽略的类和方法的列表,并在加载测试类时修补它们的字节码以完全删除这些方法。

如果我没记错的话,JUnit 使用反射来查找要执行的测试方法。然后,方法重命名操作将允许您在 JUnit 找到这些方法之前删除它们。或者可以将方法修改为立即返回,无需执行任何操作。

加载时可以使用像BCEL这样​​的库来修改类。

于 2009-09-02T17:21:09.293 回答
1

如果您只想运行测试的一个子集,听起来该类有多个职责,应该重构。或者,可以将测试类分开,以便原始项目包含所有测试,但只针对一个或多个类(我猜有些测试实际上是集成测试并涉及数据库或网络),您可以排除该类( es) 你不想要。

如果你不能做任何这些,你的覆盖选项可能是最好的。每当您需要忽略扩展该类并将其添加到 Ant 排除列表中的某些方法时,请执行此过程。这样你就可以排除你不能通过的东西,并且仍然会在不修改你的构建的情况下引入所有新的测试(你没有覆盖的方法和新的测试类)。

于 2009-09-02T18:18:24.323 回答
0

如果不需要的测试在特定的类/包中,您可以在 Ant 中使用文件集排除在导入期间排除它们。

于 2009-09-02T17:05:31.943 回答
0

两种选择

  1. 与借用测试的所有者合作,将您的测试提取到一个单独的类中,您可以共享它们。
  2. 创建您自己的测试类来代理您要使用的测试类。对于您要包含的每个方法,您的类中都有一个方法。如果它们在原始方法中,您将需要构建您正在调用的测试类的实例并在方法之前和之后执行。
  3. 基于 blockjunitrunner 创建一个自定义的 Junit 运行器,并使用它来过滤掉或在你想要的测试中。
于 2015-08-28T13:23:18.690 回答