2010-06-11 125 views
2

我在測試套件中運行的一些JUnit 4測試有問題。JUnit 4測試套件問題

如果我單獨運行測試,它們的工作沒有問題,但是當它們大部分運行在套件中時,90%的測試方法失敗並出錯。我注意到,總是第一次測試正常,但其餘的都失敗了。另一件事是一些測試方法沒有以正確的順序執行(反射不能按預期工作,或者因爲方法的檢索不一定在創建的順序中)。如果有多個測試使用同名的方法,通常會發生這種情況。我試圖調試一些測試,看起來從一行到下一行,某些屬性的值變爲null

有誰知道這是什麼問題,或者如果行爲是「正常的」?

在此先感謝。

P.S: OK,測試不依賴於對方,他們沒有這樣做,他們都有@BeforeClass@Before@After@AfterClass所以之間的測試一切都清理。測試使用數據庫,但在@BeforeClass的每次測試之前數據庫都會被清除,所以這不應該是問題。

Simplefied例如:

測試套件:

import org.junit.BeforeClass; 
import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
importy testclasses...; 

@RunWith(Suite.class) 
@Suite.SuiteClasses({ Test1.class, Test2.class }) 
public class TestSuiteX { 
@BeforeClass 
public static void setupSuite() { System.out.println("Tests started"); } 
@AfterClass 
public static void setupSuite() { System.out.println("Tests started"); } 
} 

測試: 測試是在Glassfish上運行的服務器應用程序測試functionalily。

現在,這些測試擴展了一個基類,該基類具有清除數據庫和登錄名的@BeforeClass方法以及只進行註銷的@AfterClass。 這不是問題的根源,因爲在介紹此課程之前發生了同樣的事情。

該類有一些公共靜態屬性,在其他測試中未使用並實現2個controll方法。

其餘的類,在這個例子中,這兩個類擴展了基類,並且不支持繼承的controll方法。的測試類的

實施例:

imports.... 

    public class Test1 extends AbstractTestClass { 
    protected static Log log = LogFactory.getLog(Test1.class.getName()); 

    @Test 
    public void test1_A() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     creates some entities with the server api. 
     deletes a couple of entities with the server api. 

     //tests if the extities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

} 

和第二:

public class Test1 extends AbstractTestClass { 

    protected static Log log = LogFactory.getLog(Test1.class.getName()); 

    private static String keyEntity; 
    private static EntityDO entity; 

    @Test 
    public void test1_B() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     creates some entities with the server api, adds one entities key to the static attribute and one entity DO to the static attribute for the use in the next method. 
     deletes a couple of entities with the server api. 

     //tests if the extities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

    @Test 
    public void test2_B() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     deletes the 2 entities, the one retrieved by the key and the one associated with the static DO attribute 

     //tests if the deelted entities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

這是一個基本的例子,實際的測試是較複雜的,但我試圖與簡化測試和仍然它確實不行。 謝謝。

+1

您可以發佈一個測試示例並解釋您如何運行測試套件。 – 2010-06-11 10:30:38

+0

該測試套件是一個JUnit 4測試套件,它具有所有測試類的設置,並且有一個@BeforeClass和一個@AfterClass,它只提供一些次要信息(基本字符串)。 – Hypnus 2010-06-11 10:55:41

+0

您發佈的代碼留下了最重要的細節:1)AbstractTestClass,2)@BeforeClass,@Before,@After,@AfterClass方法,3)keyEntity和實體初始化的方式和時間,4)哪個測試失敗,怎麼樣 ? – 2010-06-11 15:39:11

回答

1

您似乎是在假定執行方法的順序是固定的情況下構建測試套件的。這是錯誤的 - JUnit不保證測試方法的執行順序,所以你不應該依賴它。

這是設計 - 單元測試應該完全獨立於彼此。爲了保證這一點,JUnit創建了一個獨立的新測試類實例來執行每個測試方法。因此,無論您使用某種方法設定的屬性,下一個屬性都會丟失。

如果你有共同的測試設置/拆卸代碼,你應該把它分成不同的方法,用@Before/@After註釋。這些都是在每種測試方法之前和之後執行的。

更新:你寫

數據庫每次測試前在@BeforeClass

如果這不是一個錯字被清除,這可能是你的問題的根源。 DB應該在@Before方法中清除 - @BeforeClass對於每個類只運行一次。

+0

好吧,測試不依賴於對方,但它們的方法是這樣做的,因此我不能將數據庫清理代碼放在@Before方法中,因爲這樣它將在每個方法之前清理數據庫,並且它不起作用。如果您認爲我將數據庫清理代碼放在了套件的@BeforeClass中,情況並非如此。謝謝。 – Hypnus 2010-06-11 13:07:49

+0

@Hypnus,你所說的上面的「測試」是一個測試課,對吧?顯然我們在這裏有一個術語不匹配。測試類可能包含許多測試方法。在單元測試的說法中,每個方法代表一個單獨的_test_。而這些測試 - 即**測試方法** - 不應該相互依賴。 – 2010-06-11 13:21:25

3

您描述的情況聽起來像是一個副作用問題。你提到測試單獨運行良好,但依賴於操作順序:這通常是一個關鍵症狀。

設置整套測試用例的挑戰之一是確保每個測試都從乾淨狀態開始,執行測試,然後自行清理,將所有內容都恢復爲乾淨狀態。

請記住,有些情況下標準清理例程(例如,@Before@After)是不夠的。前段時間我遇到的一個問題是在一組數據庫測試中:作爲測試的一部分,我將記錄添加到數據庫中,並且需要專門刪除剛剛添加的記錄。

因此,有時您需要添加特定的清理代碼才能恢復到原始狀態。

0

要小心如何使用@BeforeClass來設置事情的一勞永逸,並且@Before要在每次單獨測試之前設置事物。並且要小心實例變量。

如果您可以發佈出現問題的簡單示例,我們可能會提供更具體的幫助。

+0

謝謝,我會在2個小時內做一些緊急工作。 – Hypnus 2010-06-11 10:57:19

+0

我已經爲我的案例添加了一個簡化的示例。我試圖直接使用JUnit在包上運行測試,但仍然無效(某些方法在不同位置失敗)。謝謝。 – Hypnus 2010-06-11 14:13:14