簡體   English   中英

如何在 JUnit4 中按特定順序運行測試方法?

[英]How to run test methods in specific order in JUnit4?

我想按特定順序執行由@Test注釋的測試方法。

例如:

public class MyTest {
    @Test public void test1(){}
    @Test public void test2(){}
}

我想確保每次運行MyTest時都在test2() test1() ,但是我找不到像@Test(order=xx)這樣的注釋。

我認為這是 JUnit 的一個非常重要的功能,如果 JUnit 的作者不想要訂單功能,為什么?

我認為這是 JUnit 的一個非常重要的功能,如果 JUnit 的作者不想要訂單功能,為什么?

我不確定使用 JUnit 是否有一種干凈的方法可以做到這一點,據我所知,JUnit 假設所有測試都可以按任意順序執行。 從常見問題解答:

如何使用測試夾具?

(...)不保證測試方法調用的順序,因此 testOneItemCollection() 可能在 testEmptyCollection() 之前執行。 (……)

為什么會這樣? 好吧,我相信讓測試順序依賴是作者不想提倡的做法。 測試應該是獨立的,他們不應該被耦合,並且違反這將使事情難以維持,將打破單獨(明顯),運行等測試的能力

話雖如此,如果您真的想朝這個方向發展,請考慮使用 TestNG,因為它支持以任何本機順序運行測試方法(並且諸如指定方法之類的事情取決於方法組)。 Cedric Beust 解釋了如何按照 testng 中測試的執行順序執行操作

如果刪除現有的 Junit 實例,並在構建路徑中下載JUnit 4.11或更高版本,以下代碼將按名稱順序執行測試方法,按升序排序:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {

    @Test
    public void testAcreate() {
        System.out.println("first");
    }
    @Test
    public void testBupdate() {
        System.out.println("second");
    }
    @Test
    public void testCdelete() {
        System.out.println("third");
    }
}

如果訂單很重要,您應該自己下訂單。

@Test public void test1() { ... }
@Test public void test2() { test1(); ... }

特別是,如有必要,您應該列出一些或所有可能的順序排列進行測試。

例如,

void test1(); 
void test2(); 
void test3(); 


@Test
public void testOrder1() { test1(); test3(); }

@Test(expected = Exception.class)
public void testOrder2() { test2(); test3(); test1(); }

@Test(expected = NullPointerException.class)
public void testOrder3() { test3(); test1(); test2(); }

或者,對所有排列進行全面測試:

@Test
public void testAllOrders() {
    for (Object[] sample: permute(1, 2, 3)) {
        for (Object index: sample) {
            switch (((Integer) index).intValue()) {
                case 1: test1(); break; 
                case 2: test2(); break; 
                case 3: test3(); break; 
            }
        }
    }
}

在這里, permute()是一個簡單的函數,它將所有可能的排列迭代到數組的集合中。

遷移到 TestNG 似乎是最好的方法,但我在這里看不到 jUnit 的明確解決方案。 這是我為 jUnit 找到的最易讀的解決方案/格式

@FixMethodOrder( MethodSorters.NAME_ASCENDING ) // force name ordering
public class SampleTest {
    @Test
    void stage1_prepareAndTest(){}; // that's more informative that testAcreate

    @Test
    void stage2_checkSomething(){};

    @Test
    void stage2_checkSomethingElse(){};

    @Test
    void stage3_thisDependsOnStage2(){};

    @Test
    void callTimeDoesntMatter(){}
}

這確保在 stage1 之后和 stage3 之前調用 stage2 方法。

這是我在 Junit 工作時遇到的主要問題之一,我想出了以下對我來說很好的解決方案:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

public class OrderedRunner extends BlockJUnit4ClassRunner {

    public OrderedRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> list = super.computeTestMethods();
        List<FrameworkMethod> copy = new ArrayList<FrameworkMethod>(list);
        Collections.sort(copy, new Comparator<FrameworkMethod>() {

            @Override
            public int compare(FrameworkMethod f1, FrameworkMethod f2) {
                Order o1 = f1.getAnnotation(Order.class);
                Order o2 = f2.getAnnotation(Order.class);

                if (o1 == null || o2 == null) {
                    return -1;
                }

                return o1.order() - o2.order();
            }
        });
        return copy;
    }
}

還創建一個如下所示的界面:

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

public @interface Order {
public int order();
}

現在假設您有 A 類,您在其中編寫了幾個測試用例,如下所示:

(@runWith=OrderRunner.class)
Class A{
@Test
@Order(order = 1)

void method(){

//do something

}

}

所以執行將從名為“method()”的方法開始。 謝謝!

JUnit 從 5.5 開始允許在類上使用@TestMethodOrder(OrderAnnotation.class) ,在測試方法上使用@Order(1)

JUnit 舊版本允許測試方法使用類注釋運行排序:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.JVM)
@FixMethodOrder(MethodSorters.DEFAULT)

默認情況下,測試方法按字母順序運行。 因此,要設置特定的方法順序,您可以將它們命名為:

a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

或者

_1_TestWorkUnit_WithCertainState_ShouldDoSomething _2_TestWorkUnit_WithCertainState_ShouldDoSomething _3_TestWorkUnit_WithCertainState_ShouldDoSomething

您可以在此處找到示例

JUnit 5 更新(和我的意見)

我認為這是 JUnit 的一個非常重要的功能,如果 JUnit 的作者不想要訂單功能,為什么?

默認情況下,單元測試庫不會嘗試按照源文件中出現的順序執行測試。
JUnit 5 作為 JUnit 4 以這種方式工作。 為什么? 因為如果順序很重要,則意味着它們之間有一些測試是耦合的,這對於單元測試來說是不可取的
所以 JUnit 5 引入的@Nested特性遵循相同的默認方法。

但是對於集成測試,測試方法的順序可能很重要,因為一個測試方法可能會以另一種測試方法預期的方式改變應用程序的狀態。 例如,當您為電子商店結帳處理編寫集成測試時,要執行的第一個測試方法是注冊客戶端,第二個是在購物籃中添加商品,最后一個是進行結帳。 如果測試運行器不遵守該順序,則測試場景存在缺陷並且會失敗。
因此,在 JUnit 5(從 5.4 版本開始)中,您可以通過使用@TestMethodOrder(OrderAnnotation.class)注釋測試類並使用@Order(numericOrderValue)為方法指定順序來設置執行順序。順序很重要。

例如:

@TestMethodOrder(OrderAnnotation.class) 
class FooTest {

    @Order(3)
    @Test
    void checkoutOrder() {
        System.out.println("checkoutOrder");
    }

    @Order(2)
    @Test
    void addItemsInBasket() {
        System.out.println("addItemsInBasket");
    }

    @Order(1)
    @Test
    void createUserAndLogin() {
        System.out.println("createUserAndLogin");
    }
}

輸出:

創建用戶和登錄

在籃子里添加物品

結帳訂單

順便說一句,指定@TestMethodOrder(OrderAnnotation.class)看起來不需要(至少在我測試的 5.4.0 版本中)。

旁注
關於問題:JUnit 5 是編寫集成測試的最佳選擇嗎? 我不認為它應該是第一個考慮的工具(Cucumber 和 co 可能經常為集成測試帶來更具體的價值和特性)但在一些集成測試用例中,JUnit 框架就足夠了。 因此,該功能存在是個好消息。

(尚未發布)更改https://github.com/junit-team/junit/pull/386引入了@SortMethodsWith https://github.com/junit-team/junit/pull/293至少可以在沒有它的情況下預測順序(在 Java 7 中它可以是非常隨機的)。

看一份 JUnit 報告。 JUnit 已經按包組織。 每個包都有(或可以有)TestSuite 類,每個類依次運行多個 TestCases。 每個 TestCase 可以有多個public void test*()形式的測試方法,每個方法實際上都會成為它們所屬的 TestCase 類的一個實例。 每個測試方法(TestCase 實例)都有一個名稱和一個通過/失敗標准。

我的管理層需要的是各個TestStep項目的概念,每個項目都報告自己的通過/失敗標准。 任何測試步驟的失敗不得妨礙后續測試步驟的執行。

過去,我這個職位的測試開發人員將 TestCase 類組織成與被測產品的部分相對應的包,為每個測試創建一個 TestCase 類,並使每個測試方法成為測試中的一個單獨的“步驟”,在 JUnit 輸出中有自己的通過/失敗標准。 每個測試用例都是一個獨立的“測試”,但是測試用例中的各個方法或測試“步驟”必須以特定的順序出現。

TestCase 方法是 TestCase 的步驟,測試設計者在每個測試步驟都有一個單獨的通過/失敗標准。 現在測試步驟混亂,測試(當然)失敗。

例如:

Class testStateChanges extends TestCase

public void testCreateObjectPlacesTheObjectInStateA()
public void testTransitionToStateBAndValidateStateB()
public void testTransitionToStateCAndValidateStateC()
public void testTryToDeleteObjectinStateCAndValidateObjectStillExists()
public void testTransitionToStateAAndValidateStateA()
public void testDeleteObjectInStateAAndObjectDoesNotExist()
public void cleanupIfAnythingWentWrong()

每個測試方法都斷言並報告自己單獨的通過/失敗標准。 為了排序而將其折疊為“一個大的測試方法”會丟失 JUnit 摘要報告中每個“步驟”的通過/失敗標准粒度。 ……這讓我的經理很不高興。 他們目前正在要求另一種選擇。

任何人都可以解釋帶有亂序測試方法排序的 JUnit 如何支持每個順序測試步驟的單獨通過/失敗標准,如上面舉例說明和我的管理層所要求的那樣?

不管文檔如何,我都認為這是 JUnit 框架中的一個嚴重回歸,它使許多測試開發人員的生活變得困難。

不確定我同意,如果我想測試“文件上傳”,然后測試“文件上傳插入的數據”,為什么我不希望它們彼此獨立? 我認為能夠單獨運行它們而不是在 Goliath 測試用例中同時運行它們是完全合理的。

當測試用例作為套件運行時,您想要的是完全合理的。

不幸的是現在沒有時間給出一個完整的解決方案,但看看類:

org.junit.runners.Suite

這允許您以特定順序調用測試用例(來自任何測試類)。

這些可用於創建功能、集成或系統測試。

這使您的單元測試沒有特定的順序(按照建議),無論您是否這樣運行它們,然后重新使用測試作為更大圖景的一部分。

我們為單元、集成和系統測試重用/繼承相同的代碼,有時是數據驅動的,有時是提交驅動的,有時是作為套件運行的。

在此處查看我的解決方案:“Junit 和 java 7。”

在本文中,我描述了如何按順序運行 junit 測試 - “就像在您的源代碼中一樣”。 將按照您的測試方法出現在類文件中的順序運行測試。

http://intellijava.blogspot.com/2012/05/junit-and-java-7.html

但正如 Pascal Thivent 所說,這不是一個好的做法。

使用 JUnit 5.4,您可以指定順序:

@Test
@Order(2)
public void sendEmailTestGmail() throws MessagingException {

你只需要注釋你的類

@TestMethodOrder(OrderAnnotation.class)

https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order

我在我的項目中使用它,效果很好!

正如其他人所說,理想情況下,測試應該獨立於執行順序。 這使得測試不那么脆弱,並允許它們獨立運行(許多 IDE 允許您選擇一種測試方法並獨立於其他測試執行它)。

話雖如此,對於集成測試,有些人更喜歡依賴方法排序。

從 JUnit 4.13 開始,您可以定義自己的類,通過擴展Ordering來重新排序測試。 有關更多詳細信息,請參閱JUnit wiki 這是使用內置Alphanumeric類使用測試方法名稱按Alphanumeric順序排列測試的示例:

import org.junit.Test;
import org.junit.runner.OrderWith;
import org.junit.runner.manipulation.Alphanumeric;

@OrderWith(Alphanumeric.class)
public class TestMethodOrder {

    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}

JUnit 4 更新

從 JUnit 4.13 @OrderWith ,可以重現 JUnit 5 @Order注釋。 @RunWith自定義BlockJUnit4ClassRunner實現相比,此解決方案更好地與 JUnit 4 集成。

這是我如何用注釋排序替換方法名稱排序( @FixMethodOrder(MethodSorters.NAME_ASCENDING) )。

@OrderWith(OrderAnnotation.class)
public class MyTest {
    @Test
    @Order(-1)
    public void runBeforeNotAnnotatedTests() {}

    @Test
    public void notAnnotatedTestHasPriority0() {}

    @Test
    @Order(1)
    public void thisTestHasPriority1() {}

    @Test
    @Order(2)
    public void thisTestHasPriority2() {}
}
/**
 * JUnit 4 equivalent of JUnit 5's {@code org.junit.jupiter.api.Order}
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Order {
    /**
     * Default order value for elements not explicitly annotated with {@code @Order}.
     *
     * @see Order#value
     */
    int DEFAULT = 0;

    /**
     * The order value for the annotated element.
     * <p>Elements are ordered based on priority where a lower value has greater
     * priority than a higher value. For example, {@link Integer#MAX_VALUE} has
     * the lowest priority.
     *
     * @see #DEFAULT
     */
    int value();
}
import org.junit.runner.Description;
import org.junit.runner.manipulation.Ordering;
import org.junit.runner.manipulation.Sorter;

/**
 * Order test methods by their {@link Order} annotation. The lower value has the highest priority.
 * The tests that are not annotated get the default value {@link Order#DEFAULT}.
 */
public class OrderAnnotation extends Sorter implements Ordering.Factory {
    public OrderAnnotation() {
        super(COMPARATOR);
    }

    @Override
    public Ordering create(Context context) {
        return this;
    }

    private static final Comparator<Description> COMPARATOR = Comparator.comparingInt(
            description -> Optional.ofNullable(description.getAnnotation(Order.class))
                                   .map(Order::value)
                                   .orElse(Order.DEFAULT));
}

未注釋的測試的默認優先級為 0。具有相同優先級的測試的順序是不確定的。

要點: https : //gist.github.com/jcarsique/df98e0bad9e88e8258c4ab34dad3c863

靈感來自:

我已經閱讀了一些答案並同意它不是最佳實踐,而是排序測試的最簡單方法 - 並且 JUnit 默認運行測試的方式是按字母名稱升序。

因此,只需按您想要的字母順序命名您的測試。 另請注意,測試名稱必須以單詞 test 開頭。 只看數字

test12 將在 test2 之前運行

所以:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond

請查看這個: https : //github.com/TransparentMarket/junit 它按照指定的順序運行測試(在編譯的類文件中定義)。 它還具有一個 AllTests 套件來首先運行由子包定義的測試。 使用 AllTests 實現可以擴展解決方案,過濾屬性(我們曾經使用 @Fast 注釋,但尚未發布)。

這是 JUnit 的擴展,可以產生所需的行為: https : //github.com/aafuks/aaf-junit

我知道這違背了 JUnit 哲學的作者,但是當在不嚴格的單元測試(如在 Java 中實踐)的環境中使用 JUnit 時,這可能非常有幫助。

我最終認為我的測試沒有按順序運行,但事實是我的異步工作一團糟。 使用並發時,您還需要在測試之間執行並發檢查。 就我而言,作業和測試共享一個信號量,因此下一個測試會掛起,直到正在運行的作業釋放鎖。

我知道這與這個問題並不完全相關,但也許可以幫助定位正確的問題

您可以使用以下代碼之一: @FixMethodOrder(MethodSorters.JVM) OR @FixMethodOrder(MethodSorters.DEFAULT) OR @FixMethodOrder(MethodSorters.NAME_ASCENDING)

在你這樣的測試課之前:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class BookTest {...}

如果要在 JUnit 5 中以特定順序運行測試方法,可以使用以下代碼。

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyClassTest { 

    @Test
    @Order(1)
    public void test1() {}

    @Test
    @Order(2)
    public void test2() {}

}

是時候轉向Junit5 了 以下是我們可以獲得的示例:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 class OrderedTests {

     @Test
     @Order(1)
     void nullValues() {}

     @Test
     @Order(2)
     void emptyValues() {}

     @Test
     @Order(3)
     void validValues() {}
 }

對於Junit4 ,將您在多個測試中的邏輯復制到一個測試方法中。

對於 JUnit 4,將這個注解放在測試類上解決了這個問題。

@FixMethodOrder(MethodSorters.JVM)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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