问题
我有一个集成测试套件。我有一个IntegrationTestBase
class用于我的所有测试扩展。此基类具有a@Before
(public void setUp()
)和@After
(public void tearDown()
)方法来建立API和DB连接。我一直在做的就是在每个测试用例中重写这两个方法并调用27743869和super.tearDown()
。然而,如果有人忘记调用超级或将它们放在错误的位置并且抛出异常并且忘记在finally或者其他内容中调用super,这可能会导致问题。
我想要做的是在基类final
上制作setUp
和tearDown
方法,然后添加我们自己的注释@Before
和@After
方法。做一些初始测试似乎总是按此顺序调用:
Base @Before
Test @Before
Test
Test @After
Base @After
但我只是担心订单无法保证并且可能会导致问题。我环顾四周,没有看到任何关于这个问题的内容。有谁知道我能做到这一点而没有任何问题吗?
码:
public class IntegrationTestBase {
@Before
public final void setUp() { *always called 1st?* }
@After
public final void tearDown() { *always called last?* }
}
public class MyTest extends IntegrationTestBase {
@Before
public final void before() { *always called 2nd?* }
@Test
public void test() { *always called 3rd?* }
@After
public final void after() { *always called 4th?* }
}
#1 热门回答(108 赞)
是的,这种行为是有保证的:
@Before
:
@Before超类方法将在当前类的方法之前运行,除非它们在当前类中被重写。没有定义其他排序。
@After
:
在超类中声明的@After方法将在当前类的那些之后运行,除非它们在当前类中被重写。
#2 热门回答(41 赞)
一个潜在的问题,以前咬过我:
我希望在每个测试类中最多只有一个@Before
方法,因为不能保证在类中定义的运行@Before
方法的顺序。通常,我会称这种方法为setUpTest()
。
但是,虽然@Before
记录为The @Before methods of superclasses will be run before those of the current class. No other ordering is defined.
,但这仅适用于标记为@Before
的每个方法在类层次结构中具有唯一名称的情况。
例如,我有以下内容:
public class AbstractFooTest {
@Before
public void setUpTest() {
...
}
}
public void FooTest extends AbstractFooTest {
@Before
public void setUpTest() {
...
}
}
我预计AbstractFooTest.setUpTest()
会在FooTest.setUpTest()
之前运行,但只有FooTest.setupTest()
被执行.AbstractFooTest.setUpTest()
根本没有被调用。
必须按如下方式修改代码才能工作:
public void FooTest extends AbstractFooTest {
@Before
public void setUpTest() {
super.setUpTest();
...
}
}
#3 热门回答(17 赞)
我认为基于@Before
和@After
的文档,正确的结论是给出方法的唯一名称。我在测试中使用以下模式:
public abstract class AbstractBaseTest {
@Before
public final void baseSetUp() { // or any other meaningful name
System.out.println("AbstractBaseTest.setUp");
}
@After
public final void baseTearDown() { // or any other meaningful name
System.out.println("AbstractBaseTest.tearDown");
}
}
和
public class Test extends AbstractBaseTest {
@Before
public void setUp() {
System.out.println("Test.setUp");
}
@After
public void tearDown() {
System.out.println("Test.tearDown");
}
@Test
public void test1() throws Exception {
System.out.println("test1");
}
@Test
public void test2() throws Exception {
System.out.println("test2");
}
}
结果给出了
AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown
这种方法的优点:AbstractBaseTest类的用户不能意外地覆盖setUp / tearDown方法。如果他们愿意,他们需要知道确切的名字,并且可以做到。
(次要)这种方法的缺点:用户无法看到setUp / tearDown之前或之后发生的事情。他们需要知道这些东西是由抽象类提供的。但我认为这就是他们使用抽象类的原因