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

发布于 2024-11-08 22:12:06 字数 1138 浏览 0 评论 0原文

我有一个集成测试套件。我有一个 IntegrationTestBase 类供我的所有测试扩展。该基类有一个 @Before (public void setUp()) 和 @After (public void TeaDown()) >) 建立API和DB连接的方法。我一直在做的只是在每个测试用例中重写这两个方法并调用 super.setUp() 和 super.tearDown() 。然而,如果有人忘记调用 super 或将它们放在错误的位置并抛出异常并且他们忘记在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?* }
}

I have an Integration Test Suite. I have a IntegrationTestBase class for all my tests to extend. This base class has a @Before (public void setUp()) and @After (public void tearDown()) method to establish API and DB connections. What I've been doing is just overriding those two methods in each testcase and calling super.setUp() and super.tearDown(). However this can cause problems if someone forgets to call the super or puts them at the wrong place and an exception is thrown and they forget to call super in the finally or something.

What I want to do is make the setUp and tearDown methods on the base class final and then just add our own annotated @Before and @After methods. Doing some initial tests it appears to always call in this order:

Base @Before
Test @Before
Test
Test @After
Base @After

but I'm just a little concerned that the order isn't guaranteed and that it could cause problems. I looked around and haven't seen anything on the subject. Does anyone know if I can do that and not have any problems?

Code:

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?* }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

清引 2024-11-15 22:12:06

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

@Before< /a>:

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

@After

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

Yes, this behaviour is guaranteed:

@Before:

The @Before methods of superclasses will be run before those of the current class, unless they are overridden in the current class. No other ordering is defined.

@After:

The @After methods declared in superclasses will be run after those of the current class, unless they are overridden in the current class.

最笨的告白 2024-11-15 22:12:06

以前困扰过我的一个潜在问题:

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

但是,尽管 @Before 被记录为 超类的 @Before 方法将在当前类的方法之前运行。没有定义其他顺序。,仅当用 @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();
    ...
  }
}

One potential gotcha that has bitten me before:

I like to have at most one @Before method in each test class, because order of running the @Before methods defined within a class is not guaranteed. Typically, I will call such a method setUpTest().

But, although @Before is documented as The @Before methods of superclasses will be run before those of the current class. No other ordering is defined., this only applies if each method marked with @Before has a unique name in the class hierarchy.

For example, I had the following:

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

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

I expected AbstractFooTest.setUpTest() to run before FooTest.setUpTest(), but only FooTest.setupTest() was executed. AbstractFooTest.setUpTest() was not called at all.

The code must be modified as follows to work:

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() {
    super.setUpTest();
    ...
  }
}
墨洒年华 2024-11-15 22:12:06

我认为根据 @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 之前或之后发生的事情。他们需要知道这些东西是由抽象类提供的。但我认为这就是他们使用抽象类的原因

I think based on the documentation of the @Before and @After the right conclusion is to give the methods unique names. I use the following pattern in my tests:

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

and

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

give as a result

AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown

Advantage of this approach: Users of the AbstractBaseTest class cannot override the setUp/tearDown methods by accident. If they want to, they need to know the exact name and can do it.

(Minor) disadvantage of this approach: Users cannot see that there are things happening before or after their setUp/tearDown. They need to know that these things are provided by the abstract class. But I assume that's the reason why they use the abstract class

以歌曲疗慰 2024-11-15 22:12:06

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

If you turn things around, you can declare your base class abstract, and have descendants declare setUp and tearDown methods (without annotations) that are called in the base class' annotated setUp and tearDown methods.

感情旳空白 2024-11-15 22:12:06

您可以使用@BeforeClass注释来确保setup()始终首先被调用。同样,您可以使用@AfterClass注释来确保总是最后调用tearDown()。

通常不建议这样做,但支持

这并不完全是您想要的 - 但它本质上会在测试运行的整个过程中保持数据库连接打开,然后在最后一劳永逸地关闭它。

You can use @BeforeClass annotation to assure that setup() is always called first. Similarly, you can use @AfterClass annotation to assure that tearDown() is always called last.

This is usually not recommended, but it is supported.

It's not exactly what you want - but it'll essentially keep your DB connection open the entire time your tests are running, and then close it once and for all at the end.

另类 2024-11-15 22:12:06

这不是对标语问题的答案,而是对问题正文中提到的问题的答案。不要使用 @Before 或 @After,而是考虑使用 @org.junit.Rule 因为它给你更多的灵活性。 ExternalResource(从 4.7 开始)是您最感兴趣的规则如果您正在管理连接。另外,如果您希望保证规则的执行顺序,请使用 RuleChain (自 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);
     }
 }

This isn't an answer to the tagline question, but it is an answer to the problems mentioned in the body of the question. Instead of using @Before or @After, look into using @org.junit.Rule because it gives you more flexibility. ExternalResource (as of 4.7) is the rule you will be most interested in if you are managing connections. Also, If you want guaranteed execution order of your rules use a RuleChain (as of 4.10). I believe all of these were available when this question was asked. Code example below is copied from ExternalResource's 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);
     }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文