131

我设置了一个带有几个测试的类,而不是使用@Before我想要一个在所有测试之前只执行一次的设置方法。Junit 4.8有可能吗?

4

13 回答 13

220

尽管我同意@assylias 的观点,使用@BeforeClass是一个经典的解决方案,但并不总是很方便。带有注解的方法@BeforeClass必须是静态的。对于一些需要测试用例实例的测试来说非常不方便。例如,基于 Spring 的测试用于@Autowired处理在 Spring 上下文中定义的服务。

在这种情况下,我个人使用带有注释的常规setUp()方法@Before并管理我的自定义static(!) boolean标志:

private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}
于 2012-08-23T08:57:01.650 回答
94

您可以使用BeforeClass注释

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}
于 2012-08-23T08:47:33.573 回答
31

JUnit 5 现在有一个 @BeforeAll 注释:

表示注解的方法应该在当前类或类层次结构中的所有@Test 方法之前执行;类似于 JUnit 4 的 @BeforeClass。此类方法必须是静态的。

JUnit 5 的生命周期注释似乎终于搞定了!您甚至无需查看即可猜出可用的注释(例如@BeforeEach @AfterAll)

于 2016-03-17T01:56:33.380 回答
10

setUp()在测试类的超类中时(例如AbstractTestBase下面),接受的答案可以修改如下:

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

这应该适用于单个非静态方法,但如果不误入复杂反射的世界,setUp()我无法生成等效方法......赏金指向任何可以的人!tearDown()

于 2015-06-29T13:36:58.677 回答
4

编辑: 我刚刚在调试时发现该类也在每次测试之前实例化。我猜@BeforeClass 注释在这里是最好的。

你也可以在构造函数上设置,测试类毕竟是一个类。我不确定这是否是一种不好的做法,因为几乎所有其他方法都已注释,但它确实有效。你可以像这样创建一个构造函数:

public UT () {
    // initialize once here
}
@Test
// Some test here...

ctor 将在测试之前被调用,因为它们不是静态的。

于 2016-02-08T11:49:20.933 回答
2

使用 Spring 的 @PostConstruct 方法完成所有初始化工作,并且此方法在任何 @Test 执行之前运行

于 2020-02-03T12:43:16.060 回答
2

JUnit 5 @BeforeAll 可以是非静态的,前提是测试类的生命周期是每个类的,即用 a 注释测试类,@TestInstance(Lifecycle.PER_CLASS)你就可以开始了

于 2020-11-26T08:40:46.747 回答
0

试试这个解决方案: https ://stackoverflow.com/a/46274919/907576 :

使用@BeforeAllMethods/@AfterAllMethods注释,您可以在实例上下文中执行 Test 类中的任何方法,其中所有注入的值都可用。

于 2017-09-18T08:43:39.680 回答
0

我的肮脏解决方案是:

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

我用它作为我所有测试用例的基础。

于 2018-03-08T09:08:30.673 回答
0

如果您不想强制声明在每个子测试上设置和检查的变量,则将其添加到 SuperTest 可以执行以下操作:

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}
于 2018-10-17T10:04:53.593 回答
0

我这样解决了这个问题:

添加到您的Base抽象类(我的意思是您在setUpDriver()方法中初始化驱动程序的抽象类)这部分代码:

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

现在,如果您的测试类将从Base抽象类扩展 -> setUpDriver()方法将在第一次 @Test 之前执行,每次运行仅一次。

于 2019-06-01T10:49:33.830 回答
0

经过一段时间的试验,这是我的解决方案。我需要这个进行春季启动测试。我尝试使用@PostConstruct,不幸的是它为每个测试执行。

public class TestClass {
    private static TestClass testClass = null;
    @Before
    public void setUp() {
        if (testClass == null) {
            // set up once
            ...
            testClass = this;
        }
    }
    @AfterClass
    public static void cleanUpAfterAll() {
        testClass.cleanUpAfterAllTests();
    }
    private void cleanUpAfterAllTests() {
        // final cleanup after all tests
        ...
    }
    @Test
    public void test1() {
        // test 1
        ...
    }
    @Test
    public void test2() {
        // test 2
        ...
    }
}
于 2021-04-15T00:53:52.203 回答
0

这是另一种建议:

我要做的是创建一个名为 _warmup 的方法,或者只是 _ 使用 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 注释测试类

这仅适用于您运行类中的所有测试

它有一个包含额外测试的缺点,它还将运行一个额外的 @Before 和 @After 通常建议您的测试方法是顺序独立的,这违反了该规则,但是为什么有人希望在报告中随机排序测试我不知道所以 NAME_ASCENDING 是我一直使用的

但是这样做的好处是使用最少的代码进行简单的设置,并且不需要扩展类/运行器等......测试运行长度更准确,因为所有设置时间都在方法 _warmup 上报告

于 2021-08-03T12:46:40.243 回答