当前,我所有的JUnit测试都从一个通用的基类扩展而来,该基类提供了带有@BeforeClass和标记的方法 @AfterClass-真正要做的就是设置一堆静态资源/服务以供测试使用。
@BeforeClass
@AfterClass
由于某些原因,这对我来说似乎很尴尬:
我想做的是以某种方式将当前的BeforeClass / AfterClass逻辑移出继承链,并移到可以由单个测试和整个套件共享的东西中。
能做到吗? 如果是这样,怎么办? (如果有关系,我正在使用JUnit 4.7,将其更新为其他版本可能会很困难)
第一个问题的解决方案是org.junit.rules.ExternalResource通过@ClassRuleJUnit 4.9中引入的,将逻辑移到与测试挂钩的扩展中:
org.junit.rules.ExternalResource
@ClassRule
public class MyTest { @ClassRule public static final TestResources res = new TestResources(); @Test public void testFoo() { // test logic here } } public class TestResources extends ExternalResource { protected void before() { // Setup logic that used to be in @BeforeClass } protected void after() { // Setup logic that used to be in @AfterClass } }
这样,以前由基类管理的资源将移出测试类层次结构,并移入更多的模块化/可使用的“资源”,这些资源可以在类运行之前创建,而在类运行之后销毁。
至于同时解决两个问题-即:作为单个测试的一部分和作为套件的一部分,具有相同的高级设置/拆卸运行-似乎对此没有任何特定的内置支持。 。 但是… , 您可以自己实现 :
只需将@ClassRule资源创建更改为工厂模式,该模式会在内部进行引用计数,以确定是否创建/销毁资源。
例如(请注意,这很粗糙,可能需要一些调整/错误处理才能确保其健壮性):
public class TestResources extends ExternalResource { private static int refCount = 0; private static TestResources currentInstance; public static TestResources getTestResources () { if (refCount == 0) { // currentInstance either hasn't been created yet, or after was called on it - create a new one currentInstance = new TestResources(); } return currentInstance; } private TestResources() { System.out.println("TestResources construction"); // setup any instance vars } protected void before() { System.out.println("TestResources before"); try { if (refCount == 0) { System.out.println("Do actual TestResources init"); } } finally { refCount++; } } protected void after() { System.out.println("TestResources after"); refCount--; if (refCount == 0) { System.out.println("Do actual TestResources destroy"); } } }
您的套件/测试类都将@ClassResource通过工厂方法使用资源:
@ClassResource
@RunWith(Suite.class) @SuiteClasses({FooTest.class, BarTest.class}) public class MySuite { @ClassRule public static TestResources res = TestResources.getTestResources(); @BeforeClass public static void suiteSetup() { System.out.println("Suite setup"); } @AfterClass public static void suiteTeardown() { System.out.println("Suite teardown"); } } public class FooTest { @ClassRule public static TestResources res = TestResources.getTestResources(); @Test public void testFoo() { System.out.println("testFoo"); } } public class BarTest { @ClassRule public static TestResources res = TestResources.getTestResources(); @Test public void testBar() { System.out.println("testBar"); } }
在运行单个测试时,重新引用不会有任何效果-“实际初始化”和“实际拆卸”将只发生一次。在套件中运行时,套件将创建TestResource,而各个测试将仅重用已实例化的TestResource(引用计数使它不会在套件中的测试之间被实际破坏和重新创建)。