简体   繁体   English

在不修改Test类的情况下排除单个JUnit Test方法?

[英]Exclude individual JUnit Test methods without modifying the Test class?

I'm currently re-using JUnit 4 tests from another project against my code. 我目前正在使用另一个项目中的JUnit 4测试来反对我的代码。 I obtain them directly from the other project's repository as part of my automated Ant build. 作为自动化Ant构建的一部分,我直接从其他项目的存储库中获取它们。 This is great, as it ensures I keep my code green against the very latest version of the tests. 这很棒,因为它可以确保我的代码在最新版本的测试中保持绿色。

However, there is a subset of tests that I never expect to pass on my code. 但是,有一部分测试我从未希望传递给我的代码。 But if I start adding @Ignore annotations to those tests, I will have to maintain my own separate copy of the test implementation, which I really don't want to do. 但是如果我开始在这些测试中添加@Ignore注释,我将不得不维护自己的测试实现的单独副本,我真的不想这样做。

Is there a way of excluding individual tests without modifying the Test source? 有没有一种方法可以在不修改测试源的情况下排除单个测试? Here's what I have looked at so far: 这是我到目前为止所看到的:

  • As far as I can see, the Ant JUnit task only allows you to exclude entire Test classes, not individual test methods - so that's no good for me, I need method granularity. 据我所知,Ant JUnit任务只允许你排除整个Test类,而不是单独的测试方法 - 这对我没有好处,我需要方法粒度。

  • I considered putting together a TestSuite that uses reflection to dynamically find and add all of the original tests, then add code to explicitly remove the tests I don't want to run. 我考虑整合一个TestSuite,它使用反射动态查找并添加所有原始测试,然后添加代码以显式删除我不想运行的测试。 But I ditched that idea when I noticed that the TestSuite API doesn't provide a method for removing tests. 但是当我注意到TestSuite API没有提供删除测试的方法时,我放弃了这个想法。

  • I can create my own Test classes that extend the original Test classes, override the specific tests I don't want to run, and annotate them with @Ignore. 我可以创建自己的Test类来扩展原始的Test类,覆盖我不想运行的特定测试,并使用@Ignore注释它们。 I then run JUnit on my subclasses. 然后我在我的子类上运行JUnit。 The downside here is that if new Test classes are added to the original project, I won't pick them up automatically. 这里的缺点是,如果将新的测试类添加到原始项目中,我将不会自动选择它们。 I'll have to monitor for new Test classes as they are added to the original project. 我将不得不监视新的Test类,因为它们被添加到原始项目中。 This is my best option so far, but doesn't feel ideal. 到目前为止,这是我最好的选择,但感觉并不理想。

  • The only other option I can think of is to run the bad tests anyway and ignore the failures. 我能想到的唯一另一个选择是无论如何都要运行错误的测试并忽略失败。 However, these tests take a while to run (and fail!) so I'd prefer to not run them at all. 但是,这些测试需要一段时间才能运行(并且失败!)所以我宁愿根本不运行它们。 Additionally, I can't see a way of telling the Ant task to ignore failures on specific test methods (again - I see how you can do it for individual Test classes, but not methods). 另外,我看不到告诉Ant任务忽略特定测试方法失败的方法(再次 - 我看看如何为单个测试类而不是方法执行此操作)。

If you can't touch the original test at all you are going to have some serious limitations. 如果您根本无法接触原始测试,那么您将面临一些严重的限制。 Your overriding sounds like the best bet, but with a couple of changes: 你的压倒性声音是最好的选择,但有一些变化:

Build the Ant tests specifically excluding the super classes, so that additional classes that you don't know about get run. 构建特别排除超类的Ant测试,以便运行您不了解的其他类。

You can use the @Rule annotation (new to JUnit 4.7) to know what test is being run and abort it (by returning an empty Statement implementation) rather than overriding specific methods, giving you more flexibility in knowing whether or not to avoid the test. 您可以使用@Rule注释(JUnit 4.7的新增内容)来了解正在运行的测试并中止它(通过返回空的Statement实现)而不是覆盖特定的方法,让您在知道是否避免测试时更灵活。 The only problem with this method is that you can't stop the @Before methods from running using this method, which may be slow. 此方法的唯一问题是您无法使用此方法停止运行@Before方法,这可能很慢。 If that is a problem (and you really can't touch the tests) then @Ignore in the overridden method is the only thing I can think of. 如果这是一个问题(你真的无法触及测试),那么在重写方法中的@Ignore是我唯一能想到的。

If, however, you can touch those tests, some additional options open up: 但是,如果您可以触摸这些测试,则会打开一些其他选项:

You could run them with a custom runner by specifying the @RunWith tag on the class. 您可以通过在类上指定@RunWith标记来使用自定义运行器运行它们。 This runner would just pass over execution to the standard runner (JUnit4.class) in that project, but in your project (via a system property or some other mechanism) would inspect the test name and not run a test. 这个运行器只是将执行传递给该项目中的标准运行器(JUnit4.class),但是在您的项目中(通过系统属性或其他一些机制)将检查测试名称而不运行测试。 This has the advantage of being the least intrusive, but the most difficult to implement (runners are hairy beasts, one of the stated goals of @Rule was to eliminate most of the need to make them). 这样做的优点是侵入性最小,但最难实现(跑步者是毛茸茸的野兽,@ Rule的既定目标之一是消除制造它们的大部分需求)。

Another is to make an assumeThat statement on the test that would check some configuration setting that would be true if that test should run. 另一个是在测试中做一个假设的声明,它会检查一些配置设置,如果该测试应该运行则该设置是真的。 That would actually involve injecting right into the test, which is most likely a deal breaker in anything remotely labeled a "separate project." 这实际上涉及注入测试,这很可能是任何远程标记为“单独项目”的交易破坏者。

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

OK, this is a rather heavyweight solution, but don't throw things at me if it sounds ridiculous. 好吧,这是一个相当重要的解决方案,但如果听起来很荒谬,不要向我扔东西。

The core of Junit4 is the org.junit.runner.Runner class, and its various subclasses, most importantly org.junit.runners.Suite . Junit4的核心是org.junit.runner.Runner类及其各种子类,最重要的是org.junit.runners.Suite These runners determine what the tests are for a given test class, using things like @Test and @Ignore. 这些运行器使用@Test和@Ignore之类的东西确定给定测试类的测试内容。

It's quite easy to create custom implementations of a runner, and normally you would hook them up by using the @RunWith annotation on your test classes, but obviously that's not an option for you. 创建一个跑步者的自定义实现非常容易,通常你可以通过在测试类上使用@RunWith注释来连接它们,但显然这不适合你。

However, in theory you could write your own Ant task, perhaps based upon the standard Ant Junit task, which takes your custom test runner and uses it directly, passing each test class to it in turn. 但是,从理论上讲,您可以编写自己的Ant任务,可能基于标准的Ant Junit任务,该任务采用您的自定义测试运行器并直接使用它,依次将每个测试类传递给它。 Your runner implementation could use an external config file which specifies which test methods to ignore. 您的运行器实现可以使用外部配置文件,该文件指定要忽略的测试方法。

It'd be quite a lot of work, and you'd have to spend time digging around in the prehistoric Ant Junit codebase to find out how it works. 这将是相当多的工作,你必须花时间在史前的Ant Junit代码库中挖掘,以了解它是如何工作的。 The investment in time may be worth it, however. 然而,时间投入可能是值得的。

It's just a shame that the Junit Ant task doesn't provide a mechanism to specify the test Runner, that would be ideal. 令人遗憾的是,Junit Ant任务没有提供指定测试Runner的机制,这是理想的。

A possibility I can think of to achieve what you want with the stated constraints is to use bytecode modification. 我可以想到用规定的约束来实现你想要的东西是使用字节码修改。 You could keep a list of classes and methods to ignore in a separate file, and patch the bytecode of the test classes as you load them to remove this methods altogether. 您可以在单独的文件中保留要忽略的类和方法的列表,并在加载它们时修补测试类的字节码以完全删除此方法。

If I am not mistaken, JUnit uses reflection to find the test methods to execute. 如果我没有弄错,JUnit使用反射来查找要执行的测试方法。 A method rename operation would then allow you to remove these methods before JUnit finds them. 然后,方法重命名操作将允许您在JUnit找到它们之前删除这些方法。 Or the method can be modified to return immediately, without performing any operation. 或者可以修改方法以立即返回,而不执行任何操作。

A library like BCEL can be used to modify the classes when loaded. BCEL这样的库可用于在加载时修改类。

If you want to run only a subset of the tests it sounds like that class has more than one responsibility and should be refactored down. 如果你只想运行一部分测试,那么听起来这个类有多个责任,应该重构。 Alternately the test class could be broken apart so that the original project had all the tests but on one or more classes(I'm guessing some of the tests are really integration tests and touch the database or network) and you could exclude the class(es) you didn't want. 或者,测试类可以拆分,以便原始项目具有所有测试,但是在一个或多个类上(我猜测某些测试实际上是集成测试并触摸数据库或网络)并且您可以排除类( es)你不想要的。

If you can't do any of that, your option of overriding is probably best. 如果你不能做到这一点,你可以选择覆盖最好。 Take the process of whenever you need to ignore some methods you extend that class and add it to your Ant exclude list. 无论何时需要忽略扩展该类的某些方法并将其添加到Ant排除列表,都需要执行此过程。 That way you can exclude what you can't pass and will still pull in all new tests (methods you didn't override and new test classes) without modifying your build. 这样你就可以排除你无法传递的内容,并且仍然会在不修改你的构建的情况下引入所有新的测试(你没有覆盖的方法和新的测试类)。

如果不需要的测试位于特定的类/包中,则可以使用Ant中的文件集排除在导入期间将其排除。

Two options 两种选择

  1. Work with the owner of the borrowed tests to extract your ones into a separate class you both can share. 与借用测试的所有者合作,将您的测试提取到您可以共享的单独课程中。
  2. Create your own test class which proxies the test class you want to use. 创建自己的测试类,代理要使用的测试类。 For each method you want to include have a method in your class. 对于要包含的每个方法,在您的类中都有一个方法。 You'll need to construct an instance of the test class you are calling and do before and after methods too if they're in the original. 你需要构建一个你正在调用的测试类的实例,并且如果它们在原始版本中,也需要在方法之前和之后执行。
  3. Create a custom Junit runner based on blockjunitrunner and use it to filter out or in the tests you want. 基于blockjunitrunner创建一个自定义Junit运行器,并使用它来过滤掉你想要的测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM