簡體   English   中英

JUNIT:為大量測試類只運行一次安裝程序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM