Java Junit@Before/@After的调用顺序是什么?

Java Junit@Before/@After的调用顺序是什么?,java,junit,installation,teardown,Java,Junit,Installation,Teardown,我有一个集成测试套件。我有一个IntegrationTestBase类用于扩展所有测试。这个基类有一个@Before(public void setUp())和@Before(public void tearDown())方法来建立API和DB连接。我所做的只是在每个测试用例中重写这两个方法,并调用super.setUp()和super.tearDown()。但是,如果有人忘记调用super或将其放置在错误的位置,并且抛出异常,并且他们忘记在finally或其他位置调用super,则这可能会导致

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

我想做的是在基类
final
上创建
setUp
tearDown
方法,然后只添加我们自己的带注释的
@Before
@After
方法。执行一些初始测试时,它似乎总是按以下顺序调用:

Base @Before
Test @Before
Test
Test @After
Base @After
但我只是有点担心订单没有保证,可能会引起问题。我环顾四周,没有看到关于这个问题的任何东西。有人知道我是否能做到而没有任何问题吗

代码:


如果您扭转局面,您可以声明基类抽象,并让后代声明在基类的带注释的安装和拆卸方法中调用的安装和拆卸方法(不带注释)。

是的,这种行为是有保证的:

:

超类的
@Before
方法将在当前类的方法之前运行,除非它们在当前类中被重写。没有定义其他顺序

:

超类中声明的
@After
方法将在当前类的方法之后运行,除非它们在当前类中被重写


您可以使用
@BeforeClass
注释来确保始终首先调用
setup()
。类似地,您可以使用
@AfterClass
注释来确保
tearDown()
始终被最后调用

通常不建议这样做,但确实如此


这并不完全是您想要的-但它基本上会在您的测试运行的整个过程中保持您的DB连接打开,然后在测试结束时将其一次性关闭。

一个潜在的问题曾经困扰过我:

我希望在每个测试类中最多有一个
@Before
方法,因为在类中定义的
@Before
方法的运行顺序不能保证。通常,我会调用这样一个方法
setUpTest()

但是,尽管
@Before
被记录为
超类的@Before方法将在当前类的方法之前运行。没有定义其他排序。
,这仅适用于在类层次结构中每个在
之前标记有
@的方法具有唯一名称的情况

例如,我有以下几点:

public class AbstractFooTest {
  @Before
  public void setUpTest() { 
     ... 
  }
}

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() { 
    ...
  }
}
我希望在
FooTest.setUpTest()
之前运行
AbstractFooTest.setUpTest()
,但只执行了
FooTest.setUpTest()
<代码>AbstractFooTest.setUpTest()
根本没有被调用

必须按如下方式修改代码才能工作:

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() {
    super.setUpTest();
    ...
  }
}

我认为,根据
@之前
@之后
的文档,正确的结论是给出方法的唯一名称。我在测试中使用以下模式:

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");
  }
}

结果

AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown
这种方法的优点:AbstractBaseTest类的用户不能意外地重写setUp/tearDown方法。如果他们想,他们需要知道确切的名字,并且能够做到


(次要)这种方法的缺点:用户看不到在安装/拆卸之前或之后发生的事情。他们需要知道这些东西是由抽象类提供的。但我认为这就是他们使用抽象类的原因。这不是对主题问题的回答,而是对问题主体中提到的问题的回答。与其使用@Before或@After,不如考虑使用它,因为它给了您更多的灵活性。(从4.7开始)是您管理连接时最感兴趣的规则。此外,如果您希望保证规则的执行顺序,请使用(从4.10开始)。我相信在提出这个问题时,所有这些都是可用的。下面的代码示例是从ExternalResource的javadocs复制的

 public static class UsesExternalResource {
  Server myServer= new Server();

  @Rule
  public ExternalResource resource= new ExternalResource() {
      @Override
      protected void before() throws Throwable {
          myServer.connect();
         };

      @Override
      protected void after() {
          myServer.disconnect();
         };
     };

  @Test
  public void testFoo() {
      new Client().run(myServer);
     }
 }

实际上,如果您要这样做,我建议您创建一个方法
setupDB()
closeDB()
,并用
@BeforeClass
@AfterClass
标记它们,并用
setup()
tearDown()替换您的before/after方法
@BeforeClass
@AfterClass
注释的方法需要是静态的。当我们想在这些方法中使用实例变量时,情况会怎样?在Powermock中使用
@BeforeClass
时会出现一个警告:它只适用于第一次测试运行。请参阅此问题:要清楚,所有
@Before
方法的执行顺序不受保证。如果有10个
@Before
方法,每个方法都可以按任意顺序执行;因此,请你用自己的话来解释,而不是引用一些模棱两可的文档?
@Before
@Before
方法是在每一个其他类方法之前运行(每个方法一次),还是在整个类方法套件之前和之后运行(每个类一次)?请参见John Q Citizen的一条重要提示:“这仅适用于在类层次结构中标记为@Before的每个方法都有唯一名称的情况。”记住这一点非常重要!我在类中的@Before(d)方法和它的超类中的另一个方法上使用了相同的方法名,在
junit-4.12
上发生了名称冲突。这条规则是否也适用于ConcordionRunner的@Before示例方法?这不是一个坏主意,但我不想在不需要的测试上强制执行约定
AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown
 public static class UsesExternalResource {
  Server myServer= new Server();

  @Rule
  public ExternalResource resource= new ExternalResource() {
      @Override
      protected void before() throws Throwable {
          myServer.connect();
         };

      @Override
      protected void after() {
          myServer.disconnect();
         };
     };

  @Test
  public void testFoo() {
      new Client().run(myServer);
     }
 }