如何在TestNG中選擇性地執行測試
1. 概述
在基於 TestNG 的大型測試套件中,我們經常會遇到大部分測試通過,但一小部分測試失敗的情況。在這種情況下重新運行整個套件會浪費時間和資源。 TestNG 提供了多種機制來只執行失敗的測試。
在本教程中,我們將探討僅重新執行失敗的 TestNG 測試方法的各種方法,以及它們的範例和用例。
2. 運行testng-failed.xml
TestNG 會在每次測試執行後自動產生testng-failed.xml檔案作為復原套件。只有當測試執行正常完成、至少有一個測試失敗或被跳過,並且啟用了預設報告器時,才會產生此檔案。該文件僅記錄失敗和跳過的測試方法,同時保留原始套件結構。這樣,我們就可以在不修改原始testng.xml.
讓我們來看看下面的程式碼,其中包含兩個測試案例——其中一個總是失敗:
public class ExecuteSelectivelyUnitTest {
@Test
public void givenTest_whenFails_thenExecuteSelectively() {
Assert.assertEquals(5, 6);
}
@Test
public void givenTest_whenPass_thenExecuteSelectively() {
Assert.assertEquals(5, 5);
}
}
現在,我們將使用以下命令運行測試:
mvn test -Dtest=ExecuteSelectivelyUnitTest
我們使用 Maven Surefire 執行測試,可以在target/surefire-reports/testng-failed.xml.讓我們來看看這個文件的內容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Failed suite [Surefire suite]" verbose="0">
<test thread-count="5" name="Surefire test(failed)" verbose="0">
<classes>
<class name="com.baeldung.testng.ExecuteSelectivelyUnitTest">
<methods>
<include name="givenTest_whenFails_thenExecuteSelectively"/>
</methods>
</class> <!-- com.baeldung.testng.ExecuteSelectivelyUnitTest -->
</classes>
</test> <!-- Surefire test(failed) -->
</suite> <!-- Failed suite [Surefire suite] -->
該檔案明確地僅包含ExecuteSelectivelyUnitTest中失敗的方法givenTest_whenFails_thenExecuteSelectively ,排除了所有通過的測試案例。現在,我們可以透過執行以下命令直接運行失敗的測試案例:
mvn test -Dsurefire.suiteXmlFiles=target/surefire-reports/testng-failed.xml
一旦我們觸發上述命令,我們可以看到 Maven 只會重新運行 testng-failed.xml 中列出的先前失敗的測試.
3. 在testng.xml中使用<include>
另一種執行選擇性測試的方法是手動建立一個testng.xml文件,其中僅包含我們想要執行的測試.不需要任何特殊的元資料;檔案結構與我們之前看到的類似。我們可以透過在<methods>部分中使用選擇性的<include>條目來新增測試名稱:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Failed suite [Failed suite [Surefire suite]]" guice-stage="DEVELOPMENT" verbose="0">
<test thread-count="5" name="Surefire test(failed)(failed)" verbose="0">
<classes>
<class name="com.baeldung.testng.ExecuteSelectivelyUnitTest">
<methods>
<include name="givenTest_whenFails_thenExecuteSelectively"/>
<include name="method-name-here"/>
</methods>
</class>
</classes>
</test>
</suite>
現在,我們可以透過執行以下命令直接執行testng.xml中指定的測試:
mvn test -Dsurefire.suiteXmlFiles=testng.xml
這種方法適用於小型或臨時測試,使我們能夠精細控制要執行的測試。但是,它需要手動編輯,隨著測試套件的增長,維護難度會越來越大。
4. 使用 Maven Surefire 單方法執行
我們可以透過向mvn指令傳遞-Dtest=”TestClassName#TestMethodName”來讓 Maven Surefire 外掛程式執行單一測試方法。
現在,讓我們執行ExecuteSelectivelyUnitTest類別中的givenTest_whenFails_thenExecuteSelectively()方法:
$ mvn test -Dtest=ExecuteSelectivelyUnitTest#givenTest_whenFails_thenExecuteSelectively
...
[INFO] Scanning for projects...
...
[INFO] -------------------------------------------------------
[INFO] TESTS
[INFO] -------------------------------------------------------
[INFO] Running com.baeldung.testng.ExecuteSelectivelyUnitTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.379 s <<< FAILURE! -- in com.baeldung.testng.ExecuteSelectivelyUnitTest
[ERROR] com.baeldung.testng.ExecuteSelectivelyUnitTest.givenTest_whenFails_thenExecuteSelectively -- Time elapsed: 0.006 s <<< FAILURE!
java.lang.AssertionError: expected [6] but found [5]
...
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] ExecuteSelectivelyUnitTest.givenTest_whenFails_thenExecuteSelectively:9 expected [6] but found [5]
[INFO]
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
如我們所見,這次我們只執行了指定的測試方法。
5. 透過@BeforeMethod進行選擇性執行
TestNG 總是會在執行測試之前執行諸如@BeforeMethod和@BeforeClass之類的設定方法。當我們在這些方法中拋出SkipException時,TestNG 會將其視為有意跳過測試。此時,我們可以評估條件並拋出SkipException ,從而選擇性地跳過某些測試,而無需修改測試套件的定義。
讓我們來看看下面的程式碼:
private static final Set<String> SKIP_METHODS = Set.of("givenTest_whenFails_thenExecuteSelectively");
@BeforeMethod
public void skipSelectedMethods(Method method) {
if (SKIP_METHODS.contains(method.getName())) {
throw new SkipException("Skipping test method: " + method.getName());
}
}
在這裡,我們維護了一個待跳過測試方法名稱集合.每次測試運行前,我們會將目前方法名稱與該集合進行比較,如果找到匹配項,則拋出SkipException異常。這樣,我們就可以在不修改測試套件或註解的情況下,動態地跳過特定的測試。
6. 使用IMethodInterceptor
IMethodInterceptor是 TestNG 的一個接口,它允許我們在測試運行開始之前控制要執行的測試方法。這種機制使我們能夠在測試發現階段就決定哪些測試方法應該被包含、跳過或重新排序。
我們實作了IMethodInterceptor介面並重寫了intercept()方法。 TestNG 呼叫此方法一次,並傳遞一個包含所有已發現測試方法的清單。在這個方法內部,我們定義了一個要跳過的測試方法集合。這確保了 TestNG 永遠不會調度或執行這些被跳過的方法:
public class SkipMethodInterceptor implements IMethodInterceptor {
private static final Set<String> SKIP_METHODS = Set.of("givenTest_whenFails_thenExecuteSelectively");
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
return methods.stream()
.filter(m -> !SKIP_METHODS.contains(m.getMethod().getMethodName()))
.collect(Collectors.toList());
}
}
要跳過givenTest_whenFails_thenExecuteSelectively測試,我們需要將此攔截器附加到我們的測試中,方法是將其註冊到 TestNG。我們可以使用@Listeners註解測試類並直接引用攔截器類,如下所示:
@Listeners(SkipMethodInterceptor.class)
public class ExecuteSelectivelyUnitTest {
// tests here
}
這種方法可以避免執行不必要的設定邏輯,並保持測試選擇邏輯的集中性和靈活性。
7. IDE驅動程式的選擇性執行
現代 Java 測試框架和 IDE 可以無縫協作。我們可以直接從 IDE 運行方法或類別層級的特定測試,無需修改測試套件檔案或新增任何配置。
在 IntelliJ IDEA 中,我們可以直接從編輯器執行特定的 TestNG 測試,而無需修改testng.xml.我們需要打開測試類,將遊標放在帶有@Test註解的方法上,然後單擊側邊欄中的綠色圖標,或者右鍵單擊並選擇“運行”,如下圖所示:
這種方法無需任何設定、無需分組註解,也無需更改測試套件。它使我們能夠快速迭代、立即調試故障,並在不影響測試套件中其他測試的情況下驗證修復。
8. 結論
本文討論了在 TestNG 中選擇性執行測試的各種方法。
我們已經了解了 TestNG 如何透過testng-failed.xml和 testng.xml 中的<include>指令來支援選擇性執行testng.xml.**這些方法可以有效地重新運行失敗的測試,並在 CI 管線中控制執行。 Maven** Surefire 的單次測試執行功能進一步增強了這一特性,它允許透過命令列驅動的重新運行來避免修改測試套件檔案。
IntelliJ 的 IDE 驅動執行方式因其無需配置、速度快且內建偵錯功能而成為最常用的方法。當需要更高的靈活性時, IMethodInterceptor和@BeforeMethod可以實現執行前過濾,並提供一種在調試期間隔離測試的簡單方法。
和往常一樣,程式碼可以在 GitHub 上找到。