问题

我有一个集成测试套件。我有一个IntegrationTestBaseclass用于我的所有测试扩展。此基类具有a@Before(public void setUp())和@After(public void tearDown())方法来建立API和DB连接。我一直在做的就是在每个测试用例中重写这两个方法并调用27743869和super.tearDown()。然而,如果有人忘记调用超级或将它们放在错误的位置并且抛出异常并且忘记在finally或者其他内容中调用super,这可能会导致问题。

我想要做的是在基类final上制作setUptearDown方法,然后添加我们自己的注释@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之前或之后发生的事情。他们需要知道这些东西是由抽象类提供的。但我认为这就是他们使用抽象类的原因


原文链接