TestNG 包括的チートシート
インストール
| プラットフォーム/ツール | インストール方法 |
|---|
| Maven | Add to pom.xml:
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</version> <scope>test</scope>
</dependency> |
| Gradle | Add to build.gradle:
testImplementation 'org.testng:testng:7.8.0' |
| Eclipse IDE | ヘルプ → Eclipse Marketplace → “TestNG” を検索 → インストール |
| IntelliJ IDEA | デフォルトでバンドル(または ファイル → 設定 → プラグイン → マーケットプレイス → “TestNG”) |
| VS Code | code --install-extension vscjava.vscode-java-pack
code --install-extension testng.testng |
| Manual (Linux/macOS) | wget https://repo1.maven.org/maven2/org/testng/testng/7.8.0/testng-7.8.0.jar
export CLASSPATH=$CLASSPATH:/path/to/testng-7.8.0.jar |
| Manual (Windows) | Download JAR from Maven Central
set CLASSPATH=%CLASSPATH%;C:\path\to\testng-7.8.0.jar |
コアアノテーション
| アノテーション | 説明 |
|---|
@Test | テストメソッドとしてメソッドをマークします |
@Test(priority = 1) | 実行順序を設定します(数値が小さいものが先に実行されます) |
@Test(description = "...") | レポート用のテストに説明テキストを追加 |
@Test(timeOut = 5000) | タイムアウト(ミリ秒)を超えた場合にテストに失敗します |
@Test(expectedExceptions = Exception.class) | 特定の例外がスローされることを期待する |
@Test(enabled = false) | テストを無効化/スキップする |
@Test(groups = {"smoke", "regression"}) | 1つまたは複数のグループにテストを割り当てる |
@Test(dependsOnMethods = {"testMethod"}) | 指定されたメソッド完了後に実行されます |
@Test(dependsOnGroups = {"smoke"}) | 指定されたグループ内のすべてのテスト後に実行されます |
@Test(alwaysRun = true) | 依存関係が失敗しても、テストを実行します |
@Test(invocationCount = 3) | テストを複数回実行 |
@Test(threadPoolSize = 5) | 並列スレッドで複数の呼び出しを実行 |
@BeforeMethod | Executes before each @Test method |
@AfterMethod | Executes after each @Test method |
@BeforeClass | クラス内の任意のテストメソッドの前に1回実行されます |
@AfterClass | クラス内のすべてのテストメソッドの後に1回実行されます |
@BeforeTest | Executes before any test method in <test> tag |
@AfterTest | Executes after all test methods in <test> tag |
@BeforeSuite | スイート内のすべてのテストの前に1回実行されます |
@AfterSuite | スイート内のすべてのテストの後に1回実行されます |
@BeforeGroups | 指定されたグループの最初のテストメソッドの前に実行されます |
@AfterGroups | 指定されたグループの最後のテストメソッド後に実行されます |
@DataProvider | パラメータ化のためのメソッドをテストするデータを提供します |
@Parameters | Injects parameters from testng.xml into test methods |
@Factory | テストインスタンスを動的に作成します |
@Listeners | テストクラスにカスタムリスナーをアタッチする |
コマンドライン実行
| コマンド | 説明 |
|---|
java -cp "classes:lib/*" org.testng.TestNG testng.xml | XML スイートファイルを使用してテストを実行する |
java -cp "classes:lib/*" org.testng.TestNG -testclass com.example.MyTest | 特定のテストクラスを実行 |
java -cp "classes:lib/*" org.testng.TestNG -testclass Test1,Test2 | 複数のテストクラス(カンマ区切り)を実行 |
java -cp "classes:lib/*" org.testng.TestNG -groups smoke testng.xml | 特定のグループからテストを実行 |
java -cp "classes:lib/*" org.testng.TestNG -excludegroups slow testng.xml | 実行から特定のグループを除外する |
java -cp "classes:lib/*" org.testng.TestNG -d test-output testng.xml | レポートの出力ディレクトリを指定 |
java -cp "classes:lib/*" org.testng.TestNG -parallel methods -threadcount 5 | スレッド数で並列にテストを実行 |
java -cp "classes:lib/*" org.testng.TestNG -verbose 10 testng.xml | 詳細レベルを設定 (0-10、数値が高いほど詳細) |
java -cp "classes:lib/*" org.testng.TestNG -methods MyTest.test1,MyTest.test2 | 特定のテストメソッドを実行 |
java -cp "classes:lib/*" org.testng.TestNG -suitename "MySuite" -testname "MyTest" | スイートとテストの名前をオーバーライド |
java -cp "classes:lib/*" org.testng.TestNG -reporter org.testng.reporters.EmailableReporter | 特定のレポーターを使用する |
java -cp "classes:lib/*" org.testng.TestNG -listener com.example.MyListener | カスタムリスナーを追加 |
Mavenコマンド
| コマンド | 説明 |
|---|
mvn test | すべてのテストを実行 |
mvn test -Dtest=MyTestClass | 特定のテストクラスを実行 |
mvn test -Dtest=MyTestClass#testMethod | 特定のテストメソッドを実行 |
mvn test -Dtest=MyTestClass#test* | パターンに一致するテストメソッドを実行 |
mvn test -DsuiteXmlFile=smoke-tests.xml | 特定のスイートXMLファイルを実行 |
mvn test -Dgroups=smoke,regression | 特定のテストグループを実行 |
mvn test -DexcludedGroups=slow | 特定のテストグループを除外 |
mvn test -Denvironment=staging -Dbrowser=chrome | システムプロパティをテストに渡す |
mvn test -DskipTests | テスト実行をスキップ |
mvn test -Dmaven.test.failure.ignore=true | テストが失敗しても、ビルドを継続する |
mvn test -Dparallel=methods -DthreadCount=4 | テストを並列で実行 |
mvn clean test | 以前のビルドをクリーンにし、テストを実行する |
mvn test -X | デバッグ出力でテストを実行 |
mvn surefire-report:report | HTMLテストレポートを生成 |
Gradleコマンド
| コマンド | 説明 |
|---|
gradle test | すべてのテストを実行 |
gradle test --tests MyTestClass | 特定のテストクラスを実行 |
gradle test --tests MyTestClass.testMethod | 特定のテストメソッドを実行 |
gradle test --tests *IntegrationTest | パターンに一致するテストを実行 |
gradle test --tests MyTestClass --tests OtherTest | 複数のテストクラスを実行する |
gradle test -Denvironment=staging | システムプロパティを渡す |
gradle clean test | テストをクリーンにして実行する |
gradle test --info | 詳細なログ出力で実行 |
gradle test --debug | デバッグレベルのログで実行 |
gradle test --rerun-tasks | 最新の状態でも強制的に再実行 |
gradle test --continue | テスト失敗後も実行を継続する |
gradle test --fail-fast | 最初のテスト失敗で実行を停止 |
アサーションメソッド
| メソッド | 説明 |
|---|
Assert.assertEquals(actual, expected) | 2つの値が等しいことを確認する |
Assert.assertEquals(actual, expected, "message") | カスタム失敗メッセージを使用したアサート |
Assert.assertNotEquals(actual, expected) | 2つの値が等しくないことを確認する |
Assert.assertTrue(condition) | 条件が真であることを確認する |
Assert.assertFalse(condition) | 条件が偽であることを確認する |
Assert.assertNull(object) | オブジェクトが null であることを確認する |
Assert.assertNotNull(object) | オブジェクトが null でないことを確認する |
Assert.assertSame(actual, expected) | 同じオブジェクト参照を確認する |
Assert.assertNotSame(actual, expected) | 異なるオブジェクト参照を検証する |
Assert.fail("message") | テストを明示的に失敗させる |
Assert.assertThrows(Exception.class, () -> {...}) | 例外がスローされることを確認する |
Assert.expectThrows(Exception.class, () -> {...}) | assertThrows と同じ(エイリアス) |
データプロバイダ
| パターン | 説明 |
|---|
@DataProvider(name = "testData") | データプロバイダーメソッドを定義する |
@Test(dataProvider = "testData") | テストでデータプロバイダーを使用する |
@DataProvider(parallel = true) | データプロバイダの反復処理を並列に実行する |
Object[][] dataProvider() | テストデータの2D配列を返す |
Iterator<Object[]> dataProvider() | 大規模なデータセットのためのイテレータを返す |
@DataProvider(indices = {0, 2, 4}) | 特定のデータセットインデックスのみを実行 |
データプロバイダの例
@DataProvider(name = "loginData")
public Object[][] getLoginData() {
return new Object[][] {
{"user1", "pass1", true},
{"user2", "pass2", false},
{"user3", "pass3", true}
};
}
@Test(dataProvider = "loginData")
public void testLogin(String username, String password, boolean expected) {
boolean result = login(username, password);
Assert.assertEquals(result, expected);
}
TestNG XMLコンフィグレーション
基本スイート設定
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Test Suite" parallel="methods" thread-count="5" verbose="1">
<!-- Suite-level parameters -->
<parameter name="browser" value="chrome"/>
<parameter name="environment" value="staging"/>
<!-- Define test groups -->
<test name="Smoke Tests">
<groups>
<run>
<include name="smoke"/>
<exclude name="slow"/>
</run>
</groups>
<!-- Specify test classes -->
<classes>
<class name="com.example.LoginTest"/>
<class name="com.example.SearchTest">
<!-- Include specific methods -->
<methods>
<include name="testBasicSearch"/>
<include name="testAdvancedSearch"/>
</methods>
</class>
</classes>
</test>
<!-- Another test configuration -->
<test name="Regression Tests">
<packages>
<package name="com.example.regression.*"/>
</packages>
</test>
<!-- Listeners -->
<listeners>
<listener class-name="com.example.CustomListener"/>
</listeners>
</suite>
並列実行設定
<!-- Parallel at suite level -->
<suite name="Parallel Suite" parallel="tests" thread-count="3">
<test name="Test1">...</test>
<test name="Test2">...</test>
</suite>
<!-- Parallel options: methods, tests, classes, instances -->
Maven Surefireプラグイン設定
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<!-- Specify suite files -->
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
<suiteXmlFile>smoke-tests.xml</suiteXmlFile>
</suiteXmlFiles>
<!-- Run specific groups -->
<groups>smoke,regression</groups>
<excludedGroups>slow,manual</excludedGroups>
<!-- Parallel execution -->
<parallel>methods</parallel>
<threadCount>5</threadCount>
<!-- System properties -->
<systemPropertyVariables>
<browser>chrome</browser>
<environment>staging</environment>
</systemPropertyVariables>
<!-- Continue on failures -->
<testFailureIgnore>false</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</build>
Gradleテスト設定
test {
useTestNG() {
// Suite files
suites 'src/test/resources/testng.xml'
// Include/exclude groups
includeGroups 'smoke', 'regression'
excludeGroups 'slow'
// Parallel execution
parallel = 'methods'
threadCount = 5
// Preserve order
preserveOrder = true
// Group by instances
groupByInstances = true
}
// System properties
systemProperty 'browser', 'chrome'
systemProperty 'environment', 'staging'
// Test output
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
}
一般的なユースケース
ユースケース1: セットアップとティアダウンを含む基本的なテストクラス
import org.testng.annotations.*;
import org.testng.Assert;
public class UserManagementTest {
private DatabaseConnection db;
private UserService userService;
@BeforeClass
public void setupClass() {
// Initialize database connection once for all tests
db = new DatabaseConnection("jdbc:mysql://localhost:3306/testdb");
db.connect();
}
@BeforeMethod
public void setupMethod() {
// Create fresh service instance before each test
userService = new UserService(db);
}
@Test(priority = 1, groups = {"smoke"})
public void testCreateUser() {
User user = userService.createUser("john@example.com", "John Doe");
Assert.assertNotNull(user.getId());
Assert.assertEquals(user.getEmail(), "john@example.com");
}
@Test(priority = 2, dependsOnMethods = {"testCreateUser"})
public void testFindUser() {
User user = userService.findByEmail("john@example.com");
Assert.assertNotNull(user);
Assert.assertEquals(user.getName(), "John Doe");
}
@AfterMethod
public void cleanupMethod() {
// Clean up test data after each test
userService.deleteAllUsers();
}
@AfterClass
public void cleanupClass() {
// Close database connection after all tests
db.disconnect();
}
}
ユースケース2: データプロバイダを使用したデータ駆動テスト
import org.testng.annotations.*;
import org.testng.Assert;
public class LoginTest {
private LoginPage loginPage;
@BeforeMethod
public void setup() {
loginPage = new LoginPage();
loginPage.open();
}
@DataProvider(name = "loginCredentials")
public Object[][] getLoginData() {
return new Object[][] {
{"valid@user.com", "ValidPass123", true, "Dashboard"},
{"invalid@user.com", "WrongPass", false, "Invalid credentials"},
{"", "password", false, "Email is required"},
{"user@test.com", "", false, "Password is required"},
{"admin@test.com", "AdminPass!", true, "Admin Panel"}
};
}
@Test(dataProvider = "loginCredentials")
public void testLogin(String email, String password,
boolean shouldSucceed, String expectedMessage) {
loginPage.enterEmail(email);
loginPage.enterPassword(password);
loginPage.clickLogin();
if (shouldSucceed) {
Assert.assertTrue(loginPage.isLoggedIn());
Assert.assertEquals(loginPage.getPageTitle(), expectedMessage);
} else {
Assert.assertTrue(loginPage.hasError());
Assert.assertTrue(loginPage.getErrorMessage().contains(expectedMessage));
}
}
@AfterMethod
public void teardown() {
loginPage.close();
}
}
ユースケース3: グループを使用した並列テスト実行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel Test Suite" parallel="tests" thread-count="3">
<test name="Chrome Tests" parallel="methods" thread-count="2">
<parameter name="browser" value="chrome"/>
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<classes>
<class name="com.example.tests.HomePageTest"/>
<class name="com.example.tests.SearchTest"/>
</classes>
</test>
<test name="Firefox Tests" parallel="methods" thread-count="2">
<parameter name="browser" value="firefox"/>
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<classes>
<class name="com.example.tests.HomePageTest"/>
<class name="com.example.tests.SearchTest"/>
</classes>
</test>
<test name="API Tests" parallel="classes" thread-count="3">
<groups>
<run>
<include name="api"/>
</run>
</groups>
<packages>
<package name="com.example.api.*"/>
</packages>
</test>
</suite>
// Test class using parameters
public class CrossBrowserTest {
private WebDriver driver;
@Parameters({"browser"})
@BeforeMethod
public void setup(String browser) {
if (browser.equalsIgnoreCase("chrome")) {
driver = new ChromeDriver();
} else if (browser.equalsIgnoreCase("firefox")) {
driver = new FirefoxDriver();
}
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
@Test(groups = {"smoke"})
public void testHomePage() {
driver.get("https://example.com");
Assert.assertEquals(driver.getTitle(), "Example Domain");
}
@AfterMethod
public void teardown() {
if (driver != null) {
driver.quit();
}
}
}
ユースケース4: リトライロジックを使用したAPIテスト
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
// Retry analyzer for flaky tests
public class RetryAnalyzer implements IRetryAnalyzer {
private int retryCount = 0;
private static final int MAX_RETRY = 3;
@Override
public boolean retry(ITestResult result) {
if (retryCount < MAX_RETRY) {
retryCount++;
return true;
}
return false;
}
}
// API Test class
public class APITest {
private RestClient client;
@BeforeClass
public void setup() {
client = new RestClient("https://api.example.com");
}
@Test(groups = {"api"}, retryAnalyzer = RetryAnalyzer.class)
public void testGetUser() {
Response response = client.get("/users/1");
Assert.assertEquals(response.getStatusCode(), 200);
Assert.assertNotNull(response.jsonPath().getString("name"));
}
@Test(groups = {"api"}, dependsOnMethods = {"testGetUser"})
public void testCreateUser() {
String payload = "{\"name\":\"John\",\"email\":\"john@test.com\"}";
Response response = client.post("/users", payload);
Assert.assertEquals(response.getStatusCode(), 201);
}
@Test(groups = {"api"}, timeOut = 5000)
public void testPerformance() {
long startTime = System.currentTimeMillis();
Response response = client.get("/users");
long endTime = System.currentTimeMillis();
Assert.assertEquals(response.getStatusCode(), 200);
Assert.assertTrue((endTime - startTime) < 3000,
"API response time exceeded 3 seconds");
}
}
ユースケース5: カスタムリスナーとレポーティング
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.ITestContext;
public class CustomTestListener implements ITestListener {
@Override
public void onTestStart(ITestResult result) {
System.out.println("Starting test: " + result.getName());
}
@Override
public void onTestSuccess(ITestResult result) {
System.out.println("Test passed: " + result.getName());
}
@Override
public void onTestFailure(ITestResult result) {
System.out.println("Test failed: " + result.getName());
// Take screenshot, log error, etc.
captureScreenshot(result.getName());
}
@Override
public void onTestSkipped(ITestResult result) {
System.out.println("Test skipped: " + result.getName());
}
@Override
public void onFinish(ITestContext context) {
System.out.println("Total tests run: " + context.getAllTestMethods().length);
System.out.println("Passed: " + context.getPassedTests().size());
System.out.println("Failed: " + context.getFailedTests().size());
System.out.println("Skipped: " + context.getSkippedTests().size());
}
private void captureScreenshot(String testName) {
// Screenshot logic here
}
}
// Using the listener
@Listeners(CustomTestListener.class)
public class MyTest {
@Test
public void testExample() {
Assert.assertTrue(true);
}
}
ベストプラクティス
- 意味のあるテスト名を使用する: テストを明確に名付け、何を検証するかを説明する(例:
testUserCanLoginWithValidCredentialsの代わりに
Would you like me to provide the specific translations for the numbered placeholders?test1)
-
Leverage groups effectively: Organize tests into logical groups (smoke, regression, api, ui) to run subsets of tests based on context and save execution time
-
Implement proper setup and teardown: Use @BeforeMethod/@AfterMethod for test-level setup and @BeforeClass/@AfterClass for expensive operations like database connections
-
Make tests independent: Each test should be self-contained and not rely on execution order or shared state. Use dependsOnMethods sparingly and only when logical dependency exists
-
Use DataProviders for test data: Separate test data from