[英]JUNIT : run setup only once for a large number of test classes
我有一個類,用作單元測試的基礎。 在這個類中,我為我的測試初始化整個環境,設置數據庫映射,在多個表中輸入許多數據庫記錄等。該類有一個帶有 @BeforeClass 注釋的方法,它執行初始化。 接下來,我使用具有 @Test 方法的特定類擴展該類。
我的問題是,由於所有這些測試類的 before 類完全相同,我如何確保它們對所有測試只運行一次。 一個簡單的解決方案是我可以將所有測試放在一個班級中。 然而,測試的數量巨大,它們也是根據功能頭進行分類的。 因此,它們位於不同的類中。 但是,由於它們需要完全相同的設置,因此它們繼承了@BeforeClass。 因此,每個測試類至少完成一次整個設置,總共花費的時間比我希望的要多得多。
但是,我可以將它們全部放在一個包下的各種子包中,因此如果有辦法,我可以如何為該包中的所有測試運行一次設置,那就太好了。
使用 JUnit4 測試套件,您可以執行以下操作:
@RunWith(Suite.class)
@Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
@BeforeClass
public static void setUp()
{
System.out.println("Runs before all tests in the annotation above.");
}
@AfterClass
public static void tearDown()
{
System.out.println("Runs after all tests in the annotation above.");
}
}
然后像運行普通測試類一樣運行這個類,它將運行所有測試。
JUnit 不支持這一點,您將不得不對單例使用標准的 Java 解決方法:將公共設置代碼移動到靜態代碼塊中,然后在此類中調用一個空方法:
static {
...init code here...
}
public static void init() {} // Empty method to trigger the execution of the block above
確保所有測試都調用init()
,例如我將它放入@BeforeClass
方法中。 或者把靜態代碼塊放到共享基類中。
或者,使用全局變量:
private static boolean initialize = true;
public static void init() {
if(!initialize) return;
initialize = false;
...init code here...
}
為所有測試創建一個基類:
public class BaseTest {
static{
/*** init code here ***/
}
}
每個測試都應該繼承它:
public class SomeTest extends BaseTest {
}
您可以使用@BeforeClass
方法創建一個BaseTest
類,然后讓所有其他測試繼承自它。 這樣,當每個測試對象被構建時,@ @BeforeClass
就會被執行。
還要避免對所有測試套件只執行一次,因為所有測試用例都應該是獨立的。 @BeforeClass
每個測試用例應該只執行一次,而不是測試套件。
如果您可以容忍將 spring-test 添加到您的項目中,或者您已經在使用它,那么一個好的方法是使用這里描述的技術: How to load DBUnit test data once per case with Spring Test
不確定是否有人仍在使用 JUnit 並嘗試在不使用 Spring Runner(也就是沒有 spring 集成)的情況下修復它。 TestNG 有這個功能。 但這是一個基於 JUnit 的解決方案。
像這樣為每個線程操作創建一個 RunOnce。 這維護了操作已運行的類的列表。
public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();
public void run(Function f) {
if (t.get() == null) {
t.set(Arrays.asList(getClass()));
f.apply(0);
} else {
if (!((List) t.get()).contains(getClass())) {
((List) t.get()).add(getClass());
f.apply(0);
}
}
}
}
回到你的單元測試
@Before
public beforeTest() {
operation.run(new Function<Integer, Void>() {
@Override
public Void apply(Integer t) {
checkBeanProperties();
return null;
}
});
}
private void checkBeanProperties() {
//I only want to check this once per class.
//Also my bean check needs instance of the class and can't be static.
}
My function interface is like this:
interface Function<I,O> {
O apply(I i);
}
使用這種方式時,您可以使用 ThreadLocal 對每個類執行一次操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.