我设置了一个带有几个测试的类,而不是使用@Before
我想要一个在所有测试之前只执行一次的设置方法。Junit 4.8有可能吗?
13 回答
尽管我同意@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;
}
您可以使用BeforeClass
注释:
@BeforeClass
public static void setUpClass() {
//executed only once, before the first test
}
JUnit 5 现在有一个 @BeforeAll 注释:
表示注解的方法应该在当前类或类层次结构中的所有@Test 方法之前执行;类似于 JUnit 4 的 @BeforeClass。此类方法必须是静态的。
JUnit 5 的生命周期注释似乎终于搞定了!您甚至无需查看即可猜出可用的注释(例如@BeforeEach @AfterAll)
当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 可以是非静态的,前提是测试类的生命周期是每个类的,即用 a 注释测试类,@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 之前执行,每次运行仅一次。
经过一段时间的试验,这是我的解决方案。我需要这个进行春季启动测试。我尝试使用@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
...
}
}
这是另一种建议:
我要做的是创建一个名为 _warmup 的方法,或者只是 _ 使用 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 注释测试类
这仅适用于您运行类中的所有测试
它有一个包含额外测试的缺点,它还将运行一个额外的 @Before 和 @After 通常建议您的测试方法是顺序独立的,这违反了该规则,但是为什么有人希望在报告中随机排序测试我不知道所以 NAME_ASCENDING 是我一直使用的
但是这样做的好处是使用最少的代码进行简单的设置,并且不需要扩展类/运行器等......测试运行长度更准确,因为所有设置时间都在方法 _warmup 上报告