一次运行设置方法

我设置了一个包含两个测试的类,而不是使用 @Before,我希望有一个在所有测试之前只执行一次的 setup 方法。JUnit 4.8有可能吗?

151968 次浏览

你可以使用 BeforeClass注释:

@BeforeClass
public static void setUpClass() {
//executed only once, before the first test
}

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

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

private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
if (setUpIsDone) {
return;
}
// do the setup
setUpIsDone = true;
}

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()没有迷失到一个复杂的反射世界... 奖金点给任何人谁可以!

编辑: 我刚刚在调试时发现这个类在每次测试之前都被实例化了。 我想@Before Class 注释是这里最好的。

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

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

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

JUnit 5现在有一个@Before All 注释:

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

JUnit5的生命周期注释似乎终于做对了!您甚至不用查看就可以猜出哪些注释是可用的(例如@Beforeeach@AfterAll)

我肮脏的解决办法是:

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


...


}

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

如果你不想在每个子测试中强制设置和检查变量的声明,那么将它添加到 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 ...
}


}

我是这样解决这个问题的:

添加到 基地抽象类(我指的是在 SetUpDriver ()方法中初始化驱动程序的抽象类)这部分代码:

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

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

使用 Spring 的@PostConstruction 方法执行所有初始化工作,该方法在执行任何@Test 之前运行

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

经过一段时间的实验,这是我的解决方案。我需要这个做弹簧启动测试。我试过使用@PostConstruction,不幸的是,它对每个测试都会执行。

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
...
}
}

这里有一个可供选择的建议:

我要做的就是 创建一个名为 _ warup 或 just _ 的方法 用@FixMethodOrder (MethodSorters.NAME _ ASCENding)注释测试类

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

它的缺点是包含额外的测试,这也会运行另外一个@Before 和@After 通常建议您的测试方法独立于顺序,这打破了规则,但是为什么有人喜欢在报告中随机排序的测试,我不知道,所以我总是使用 NAME _ ASCENding

但是这样做的好处是用最少的代码进行简单的设置,并且不需要扩展类/运行程序等等。 测试运行长度更加精确,因为所有的安装时间都在 method _ warm up 上报告

@BeforeClass的问题在于它在构造函数之前触发。 因此,如果您依赖于 @Autowired构造函数来提供数据,那么它就不能工作: 执行顺序错误。

类似地,@PostConstruct在调用构造函数之后触发。并且构造函数与每个 @Test一起触发,因此如果您使用这个函数,您的设置函数将与每个测试一起触发。 这与从构造函数调用函数具有完全相同的效果。

我发现唯一有效的解决方案是使用一个标志来指示是否已经执行了 setUp()方法。虽然它并不理想,但它将大大减少每次测试前的处理量。

private static boolean initialized = false;


@Autowired
public CacheTest( MyBean myBean ){


this.myBean = myBean;
}




@PostConstruct
public static void setUp(){


if( initialized ) { return };


initialized = true;
    

//do suff with myBean
}