在jUnit 4.x之前和之后套件执行挂钩

我正在尝试使用jUnit 4.4来执行testing,并进行一系列的集成testing。 拆卸需要可靠运行。 我在TestNG有其他问题,所以我正在寻找回到jUnit。 在所有testing运行之前和所有testing完成之后,哪些钩子可用于执行?

注意:我们使用maven 2来编译。 我已经尝试过使用Maven的post-integration-test pre-post-integration-test阶段,但是,如果testing失败,maven会停止并且不会运行post-integration-test ,这没有任何帮助。

是的,在testing套件的任何testing之前和之后,可以可靠地运行安装和拆卸方法。 让我用代码演示:

 package com.test; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({Test1.class, Test2.class}) public class TestSuite { @BeforeClass public static void setUp() { System.out.println("setting up"); } @AfterClass public static void tearDown() { System.out.println("tearing down"); } } 

所以你的Test1类看起来像这样:

 package com.test; import org.junit.Test; public class Test1 { @Test public void test1() { System.out.println("test1"); } } 

…你可以想象Test2看起来很相似。 如果你运行TestSuite,你会得到:

 setting up test1 test2 tearing down 

所以你可以看到,设置/拆卸只能在所有testing之前和之后进行。

catch:这只适用于运行testing套件的情况,不要将Test1和Test2作为单独的JUnittesting运行。 你提到你使用的是maven,maven surefire插件喜欢单独运行testing,而不是套件的一部分。 在这种情况下,我build议创build一个每个testing类扩展的超类。 超类然后包含注释的@BeforeClass和@AfterClass方法。 虽然不像上述方法那么干净,但我认为它会为你工作。

至于testing失败的问题,您可以设置maven.test.error.ignore,以便构build继续失败的testing。 这不是build议作为一个持续的实践,但它应该让你运作,直到所有的testing通过。 有关更多详细信息,请参阅maven surefire文档 。

我的同事build议如下:你可以使用一个自定义的RunListener,并实现testRunFinished()方法: http ://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org 。 junit.runner.Result)

要注册RunListener,只需configurationsurefire插件,如下所示: http ://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html“使用自定义侦听器和记者”

该configuration也应该由故障安全插件选取。 这个解决scheme非常棒,因为您不必指定套件,查找testing类或任何这些东西 – 它可以让Maven发挥它的魔力,等待所有的testing完成。

您可以在JUnit 4.9+中使用@ClassRule注释,正如我在回答另一个问题中所描述的那样 。

使用注释,你可以做这样的事情:

 import org.junit.*; import static org.junit.Assert.*; import java.util.*; class SomethingUnitTest { @BeforeClass public static void runBeforeClass() { } @AfterClass public static void runAfterClass() { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testSomethingOrOther() { } } 

在这里,我们

  • 升级到JUnit 4.5,
  • 编写注释来标记每个需要工作服务的testing类或方法,
  • 为包含静态方法的每个注释编写处理程序,以实现服务的build立和拆除,
  • 扩展了通常的Runner以在testing中定位注释,将静态处理程序方法添加到testing执行链中适当的位置。

假如你所有的testing都可以扩展一个“技术”类并且在同一个包中,你可以做一些小技巧:

 public class AbstractTest { private static int nbTests = listClassesIn(<package>).size(); private static int curTest = 0; @BeforeClass public static void incCurTest() { curTest++; } @AfterClass public static void closeTestSuite() { if (curTest == nbTests) { /*cleaning*/ } } } public class Test1 extends AbstractTest { @Test public void check() {} } public class Test2 extends AbstractTest { @Test public void check() {} } 

请注意,这个解决scheme有很多缺点:

  • 必须执行包的所有testing
  • 必须划分一个“技术”类
  • 你不能在子类中使用@BeforeClass和@AfterClass
  • 如果您只在包装中执行一个testing,则清洗不完成

有关信息:listClassesIn()=> 如何在Java中find给定类的所有子类?

至于“注意:我们使用maven 2来构build我已经尝试过使用maven的前后整合testing阶段,但是如果testing失败,maven会停止并且不会运行整合后testing,这是没有帮助的。“

您可以尝试使用故障安全插件,我认为它可以确保清理发生,无论设置或中间阶段状态如何

唯一的办法,我想那么得到你想要的function就是做类似的事情

 import junit.framework.Test; import junit.framework.TestResult; import junit.framework.TestSuite; public class AllTests { public static Test suite() { TestSuite suite = new TestSuite("TestEverything"); //$JUnit-BEGIN$ suite.addTestSuite(TestOne.class); suite.addTestSuite(TestTwo.class); suite.addTestSuite(TestThree.class); //$JUnit-END$ } public static void main(String[] args) { AllTests test = new AllTests(); Test testCase = test.suite(); TestResult result = new TestResult(); setUp(); testCase.run(result); tearDown(); } public void setUp() {} public void tearDown() {} } 

我在eclipse中使用了这样的东西,所以我不确定在这个环境之外的可移植性

据我所知在JUnit中没有这样做的机制,但是你可以尝试子类化Suite,并用提供钩子的版本覆盖run()方法。

由于maven-surefire-plugin不首先运行Suite类,但是将套件和testing类视为相同,因此我们可以按如下所示configuration插件以仅启用套件类并禁用所有testing。 套件将运行所有的testing。

  <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <includes> <include>**/*Suite.java</include> </includes> <excludes> <exclude>**/*Test.java</exclude> <exclude>**/*Tests.java</exclude> </excludes> </configuration> </plugin> 

如果您不想创build套件并且必​​须列出所有testing类,则可以使用reflection来dynamic查找testing类的数量,并在基类@AfterClass中进行倒计数,以仅执行一次tearDown:

 public class BaseTestClass { private static int testClassToRun = 0; // Counting the classes to run so that we can do the tear down only once static { try { Field field = ClassLoader.class.getDeclaredField("classes"); field.setAccessible(true); @SuppressWarnings({ "unchecked", "rawtypes" }) Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader()); for (Class<?> clazz : classes) { if (clazz.getName().endsWith("Test")) { testClassToRun++; } } } catch (Exception ignore) { } } // Setup that needs to be done only once static { // one time set up } @AfterClass public static void baseTearDown() throws Exception { if (--testClassToRun == 0) { // one time clean up } } } 

如果您更喜欢使用@BeforeClass而不是静态块,则也可以使用布尔标志在第一次调用时只进行一次reflection计数和testing设置。 希望这有助于某人,我花了一个下午的时间找出一个比列举套件中的所有课程更好的方法。

现在你所需要做的就是扩展这个类为你所有的testing类。 我们已经有了一个基础类来为我们所有的testing提供一些常用的东西,所以这对我们来说是最好的解决scheme。

灵感来自这个SO回答https://stackoverflow.com/a/37488620/5930242

如果你不想在任何地方扩展这个课程,最后的答案可能会做你想要的。