【发布时间】:2012-08-18 18:03:19
【问题描述】:
我设置了一个包含几个测试的类,而不是使用@Before,我希望有一个在所有测试之前只执行一次的设置方法。 Junit 4.8 可以吗?
【问题讨论】:
-
看看RunListener:stackoverflow.com/a/14773170/548473
我设置了一个包含几个测试的类,而不是使用@Before,我希望有一个在所有测试之前只执行一次的设置方法。 Junit 4.8 可以吗?
【问题讨论】:
虽然我同意@assylias 的观点,即使用@BeforeClass 是一个经典的解决方案,但并不总是很方便。带有@BeforeClass 注释的方法必须是静态的。对于一些需要测试用例实例的测试来说非常不方便。例如,基于 Spring 的测试使用 @Autowired 来处理在 spring 上下文中定义的服务。
在这种情况下,我个人使用带有 @Before 注释的常规 setUp() 方法并管理我的自定义 static(!) boolean 标志:
private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
if (setUpIsDone) {
return;
}
// do the setup
setUpIsDone = true;
}
【讨论】:
setUp() 方法位于超类中的情况外,此方法有效 - 在下方发布了answer 尝试解决此问题。
你可以使用the BeforeClass annotation:
@BeforeClass
public static void setUpClass() {
//executed only once, before the first test
}
【讨论】:
TheClassYouWant.class 代替 getClass() 调用吗?这是实际的 Java:String.class.getName()。
JUnit 5 现在有一个 @BeforeAll 注释:
表示注解的方法应该在所有@Test之前执行 当前类或类层次结构中的方法;类似于 JUnit 4 的@BeforeClass。此类方法必须是静态的。
JUnit 5 的生命周期注释似乎终于搞定了!您甚至无需查看即可猜出哪些注释可用(例如@BeforeEach @AfterAll)
【讨论】:
@BeforeClass有同样的问题,需要static。 IMO @AlexR 的解决方案更好。
当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() 生成等效方法,而不会误入复杂反射的世界......赏金指向任何可以的人!
【讨论】:
编辑: 我刚刚在调试时发现该类也在每次测试之前实例化。 我猜@BeforeClass 注释在这里是最好的。
你也可以在构造函数上设置,测试类毕竟是一个类。 我不确定这是否是一种不好的做法,因为几乎所有其他方法都已注释,但它确实有效。你可以像这样创建一个构造函数:
public UT () {
// initialize once here
}
@Test
// Some test here...
ctor 将在测试之前被调用,因为它们不是静态的。
【讨论】:
使用 Spring 的 @PostConstruct 方法完成所有初始化工作,并且此方法在任何 @Test 执行之前运行
【讨论】:
JUnit 5 @BeforeAll 可以是非静态的,前提是测试类的生命周期是每个类的,即用 @TestInstance(Lifecycle.PER_CLASS) 注释测试类,然后你就可以开始了
【讨论】:
试试这个解决方案: https://stackoverflow.com/a/46274919/907576:
使用 @BeforeAllMethods/@AfterAllMethods 注释,您可以在实例上下文中执行 Test 类中的任何方法,其中所有注入的值都可用。
【讨论】:
我的肮脏解决方案是:
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 ...
}
}
【讨论】:
我这样解决了这个问题:
将这部分代码添加到您的 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 之前执行 ONE 每次运行的时间。
【讨论】:
这里有一个替代建议:
我要做的是让这个工作 创建一个名为 _warmup 或只是 _ 的方法 用@FixMethodOrder(MethodSorters.NAME_ASCENDING)注释测试类
这仅适用于您运行类中的所有测试
它的缺点是包含额外的测试,这也会运行额外的@Before 和@After 通常建议您的测试方法与顺序无关,这违反了该规则,但是为什么有人希望在报告中随机排序测试我不知道所以 NAME_ASCENDING 是我一直使用的
但这样做的好处是设置简单,代码最少,无需扩展类/运行器等... 测试运行长度更准确,因为所有设置时间都在方法 _warmup 上报告
【讨论】:
经过一段时间的试验,这是我的解决方案。我需要这个进行春季启动测试。我尝试使用@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
...
}
}
【讨论】: