JUnit-@Before @After-实例方法仅被调用一次?怎么样?

时间:2018-12-07 17:36:23

标签: java junit junit4

我试图找到一种方法来正确实现测试类的设置和拆卸方法(与JUnit 4配合使用)。

尝试了很多事情并重新研究之后,我发现了这一点。

Difference between setUp() and setUpBeforeClass()

所以...如果是真的...我发现这种设计非常不灵活。

我的意思是...就我而言,我想为整个测试类运行一次@BeforeClass方法,即在所有测试用例方法之前运行一次,但要在我的测试类实例初始化之后运行一次。我需要将此方法作为实例方法。

似乎我做不到。它要求我将@BeforeClass方法定义为静态。

如果我尝试使用@Before实例方法,我可以看到它在每个测试用例方法之前被调用了很多次。但是我只需要调用一次。

有什么体面的方式可以做我想要的吗?我很惊讶...

这是有趣的部分:对于@Before OK ...,我可以做一些解决方法,可以定义一些布尔标志,然后检测到当前调用是第一个@Before方法调用。然后才做一些有用/实际的事情。

但是对于@After,我想检测@After方法的最后一次调用(这样,只有在最后一次调用时,我才在其中进行实际操作)。但是我无法使用任何标志检测到此最后一次调用。

我不知道JUnit的设计者怎么会想到所有这些。
或者...我想念什么吗?

2 个答案:

答案 0 :(得分:0)

JUnit 4要求@BeforeClass@AfterClass仅出现在static方法中。如果您无法将方法static设为模仿的最简单方法,那就是将静态持有人与@After配合使用:

private static MyTest lastTest;

public cleanup() {
  // actual instance cleanup
}

@After
public tearDown() {
  lastTest = this;
}

@AfterClass
public static cleanup() {
  if (lastTest != null) {
    lastTest.cleanup();
  }
}

这是一个丑陋的骇客,在某些情况下可能无法使用,并且可能会破坏与自定义运行程序的交互,例如SpringRunner。在简单的情况下可能会起作用。

要回答为什么在此用例中JUnit 4和JUnit 5都不支持非静态方法的原因,请参见this comment

  

在没有“每个测试类的测试实例”语义的情况下,要求@BeforeAll和@AfterAll方法是静态的。有关详细信息,请参见#48的说明。

     

但是,一旦解决了#48,对于可能有意义的情况,静态限制可能会被删除。

答案 1 :(得分:0)

您可以使用JUnit5(即Jupiter JUnit)完成所有这些操作。如果您确实需要使用JUnit4,则可能需要执行以下操作:

package com.jesperancinha.unittests;

import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class OneTimeSetupUnitTest extends TestCase {

    private static int up = 0;
    private static int down = 0;

    public static Test suite() {
        return new TestSetup(new TestSuite(OneTimeSetupUnitTest.class)) {
            protected void setUp() {
                System.out.println("testStart");
                up++;
                System.out.println(up);

            }

            protected void tearDown() {
                System.out.println("testEnd");
                down++;
                System.out.println(down);
            }
        };
    }

    @org.junit.Test
    public void test1() {
        System.out.println("test1");
        System.out.println(up);
        System.out.println(down);

    }

    @org.junit.Test
    public void test2() {
        System.out.println("test2");
        System.out.println(up);
        System.out.println(down);
    }
}

这样做的好处是,您不会做任何意外的事情,包括适合您的情况。

如果运行此代码片段,您应该会得到类似以下内容的信息:

  • testStart
  • 1
  • test1
  • 1
  • 0
  • test2
  • 1
  • 0
  • testEnd
  • 1

我已放置标志,以便向您显示一些跟踪信息以准确解释发生了什么。如您所见,标志“ up”在单元测试开始时立即更新。对于单个测试,它不会更改。直到测试结束,标志“ down”保持为0。仅在最后,此标志会更新。这意味着setUp仅被调用一次,而tearDown也仅被调用一次。您不需要同时使用这两种方法,因此我认为这就是您想要的。