콘텐츠로 이동

TestNG 종합 치트시트

TestNG 종합 치트시트

설치

플랫폼/도구설치 방법
MavenAdd to pom.xml:
<dependency>
  <groupId>org.testng</groupId>
  <artifactId>testng</artifactId>
  <version>7.8.0</version>
  <scope>test</scope>
</dependency>
GradleAdd to build.gradle:
testImplementation 'org.testng:testng:7.8.0'
Eclipse IDE도움말 → Eclipse Marketplace → “TestNG” 검색 → 설치
IntelliJ IDEA기본적으로 번들로 제공됨 (또는 파일 → 설정 → 플러그인 → 마켓플레이스 → “TestNG”)
VS Codecode --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"})테스트를 하나 이상의 그룹에 할당합니다
@Test(dependsOnMethods = {"testMethod"})지정된 메서드(들) 완료 후 실행됨
@Test(dependsOnGroups = {"smoke"})지정된 그룹의 모든 테스트 후에 실행됨
@Test(alwaysRun = true)의존성이 실패해도 테스트 실행
@Test(invocationCount = 3)여러 번 테스트 실행
@Test(threadPoolSize = 5)병렬 스레드에서 여러 호출을 실행합니다
@BeforeMethodExecutes before each @Test method
@AfterMethodExecutes after each @Test method
@BeforeClass클래스의 모든 테스트 메서드 이전에 한 번 실행됩니다
@AfterClass클래스의 모든 테스트 메서드 후에 한 번 실행됩니다
@BeforeTestExecutes before any test method in <test> tag
@AfterTestExecutes after all test methods in <test> tag
@BeforeSuite모든 테스트 스위트의 테스트들 이전에 한 번 실행됩니다
@AfterSuite모든 테스트 스위트의 테스트들이 끝난 후 한 번 실행됩니다
@BeforeGroups지정된 그룹의 첫 번째 테스트 메서드 이전에 실행됩니다
@AfterGroups지정된 그룹의 마지막 테스트 메서드 후에 실행됨
@DataProvider매개변수화를 위한 메서드 테스트에 데이터를 제공합니다
@ParametersInjects parameters from testng.xml into test methods
@Factory동적으로 테스트 인스턴스 생성
@Listeners테스트 클래스에 사용자 정의 리스너 연결

명령줄 실행

명령어설명
java -cp "classes:lib/*" org.testng.TestNG testng.xmlXML 스위트 파일을 사용하여 테스트 실행
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:reportHTML 테스트 보고서 생성

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)두 값이 같은지 확인
Assert.assertEquals(actual, expected, "message")사용자 정의 실패 메시지로 어설트하기
Assert.assertNotEquals(actual, expected)두 값이 같지 않은지 확인
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()대용량 데이터셋을 위한 iterator 반환
@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대신에

Note: For texts 3-20, I noticed no specific text was provided, so I’ve left them as-is. If you have specific texts for those numbers, please provide them and I’ll translate accordingly.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