Comprehensive testing framework for Java with annotations, data-driven testing, and parallel execution capabilities
TestNG's annotation system provides declarative test configuration, eliminating the need for naming conventions and providing flexible test orchestration through groups, dependencies, and data providers.
The primary annotation for marking methods and classes as tests. Provides extensive configuration options for test behavior, dependencies, grouping, and execution parameters.
/**
* Marks a method or class as a test
* @param groups - Groups this test belongs to (for selective execution)
* @param dependsOnMethods - Methods this test depends on (must succeed first)
* @param dependsOnGroups - Groups this test depends on (must succeed first)
* @param enabled - Whether this test is enabled (default: true)
* @param timeOut - Maximum time in milliseconds for test execution
* @param invocationCount - Number of times to invoke this method
* @param threadPoolSize - Size of thread pool for invocationCount > 1
* @param successPercentage - Success percentage for invocationCount > 1
* @param dataProvider - Name of data provider method
* @param dataProviderClass - Class containing the data provider method
* @param expectedExceptions - Expected exception types (test passes if thrown)
* @param priority - Priority for test method ordering
* @param description - Human-readable description of the test
* @param suiteName - Override suite name for this test
* @param testName - Override test name for this test
* @param singleThreaded - Whether test methods should run in single thread
* @param retryAnalyzer - Class to determine if failed test should be retried
*/
@Test(
groups = {"unit", "smoke"},
dependsOnMethods = {"setupMethod"},
dependsOnGroups = {"initialization"},
enabled = true,
timeOut = 5000,
invocationCount = 1,
threadPoolSize = 1,
successPercentage = 100,
dataProvider = "testData",
dataProviderClass = DataProviders.class,
expectedExceptions = {IllegalArgumentException.class},
priority = 0,
description = "Test description",
suiteName = "Custom Suite",
testName = "Custom Test",
singleThreaded = false,
retryAnalyzer = RetryAnalyzer.class
)
public void testMethod() { }Usage Examples:
// Basic test
@Test
public void simpleTest() {
Assert.assertTrue(true);
}
// Test with groups
@Test(groups = {"unit", "fast"})
public void groupedTest() {
Assert.assertEquals(2 + 2, 4);
}
// Test with dependencies
@Test
public void setupData() {
// Setup code
}
@Test(dependsOnMethods = "setupData")
public void testWithDependency() {
// This runs after setupData succeeds
}
// Test with timeout
@Test(timeOut = 1000)
public void fastTest() {
// Must complete within 1 second
}
// Test expecting exception
@Test(expectedExceptions = IllegalArgumentException.class)
public void testExpectedException() {
throw new IllegalArgumentException("Expected");
}
// Multiple invocations
@Test(invocationCount = 5, threadPoolSize = 2)
public void repeatedTest() {
// Runs 5 times with 2 threads
}Marks methods that supply data for parameterized tests. Enables data-driven testing by providing test data from various sources.
/**
* Marks a method as a data provider for parameterized tests
* @param name - Name of the data provider (defaults to method name)
* @param parallel - Whether data provider should run in parallel
* @param indices - Specific indices of data to use from the provider
* @param propagateFailureAsTestFailure - Whether data provider failures should be test failures
* @param cacheDataForTestRetries - Whether to cache data for test retries
* @param retryUsing - Retry analyzer for data provider failures
*/
@DataProvider(
name = "customName",
parallel = false,
indices = {0, 2, 4},
propagateFailureAsTestFailure = true,
cacheDataForTestRetries = false,
retryUsing = DataProviderRetryAnalyzer.class
)
public Object[][] dataProviderMethod() {
return new Object[][] {
{"param1", 123},
{"param2", 456}
};
}Usage Examples:
// Basic data provider
@DataProvider
public Object[][] basicData() {
return new Object[][] {
{"test1", 1},
{"test2", 2},
{"test3", 3}
};
}
@Test(dataProvider = "basicData")
public void testWithData(String name, int value) {
Assert.assertNotNull(name);
Assert.assertTrue(value > 0);
}
// Named data provider
@DataProvider(name = "usernames")
public Object[][] getUsernames() {
return new Object[][] {
{"alice"},
{"bob"},
{"charlie"}
};
}
@Test(dataProvider = "usernames")
public void testUsernames(String username) {
Assert.assertTrue(username.length() > 0);
}
// Parallel data provider
@DataProvider(parallel = true)
public Object[][] parallelData() {
return new Object[][] {
{1}, {2}, {3}, {4}, {5}
};
}
// Data provider with specific indices
@DataProvider(indices = {0, 2})
public Object[][] selectiveData() {
return new Object[][] {
{"first"}, // index 0 - will be used
{"second"}, // index 1 - will be skipped
{"third"} // index 2 - will be used
};
}
// Data provider from external class
public class ExternalDataProvider {
@DataProvider
public static Object[][] externalData() {
return new Object[][] { {"external"} };
}
}
@Test(dataProvider = "externalData", dataProviderClass = ExternalDataProvider.class)
public void testExternalData(String data) {
Assert.assertEquals(data, "external");
}Lifecycle annotations for setup and teardown methods that run at different scopes (method, class, test, suite, groups).
// Method-level configuration
@BeforeMethod
public void beforeEachTest() { }
@AfterMethod
public void afterEachTest() { }
// Class-level configuration
@BeforeClass
public void beforeAllTestsInClass() { }
@AfterClass
public void afterAllTestsInClass() { }
// Test-level configuration (from testng.xml)
@BeforeTest
public void beforeTest() { }
@AfterTest
public void afterTest() { }
// Suite-level configuration
@BeforeSuite
public void beforeEntireSuite() { }
@AfterSuite
public void afterEntireSuite() { }
// Group-level configuration
@BeforeGroups(groups = {"database", "integration"})
public void beforeDatabaseTests() { }
@AfterGroups(groups = {"database", "integration"})
public void afterDatabaseTests() { }Configuration Attributes:
All configuration annotations support these common attributes:
@BeforeMethod(
groups = {"setup"},
dependsOnMethods = {"globalSetup"},
dependsOnGroups = {"initialization"},
enabled = true,
alwaysRun = false,
description = "Setup method description"
)
public void setupMethod() { }Usage Examples:
public class ConfigurationExample {
@BeforeSuite
public void globalSetup() {
System.out.println("Suite started");
// Database connection, global resources
}
@BeforeClass
public void classSetup() {
System.out.println("Class setup");
// Class-level initialization
}
@BeforeMethod
public void methodSetup() {
System.out.println("Method setup");
// Fresh state for each test
}
@Test
public void testMethod1() {
System.out.println("Test 1");
}
@Test
public void testMethod2() {
System.out.println("Test 2");
}
@AfterMethod
public void methodCleanup() {
System.out.println("Method cleanup");
}
@AfterClass
public void classCleanup() {
System.out.println("Class cleanup");
}
@AfterSuite
public void globalCleanup() {
System.out.println("Suite finished");
// Release global resources
}
}Marks methods that create test instances dynamically. Enables creation of multiple test instances with different parameters or configurations.
/**
* Marks a method as a factory for creating test instances
* @param dataProvider - Data provider for factory parameters
* @param dataProviderClass - Class containing the data provider
* @param enabled - Whether factory is enabled
* @param indices - Specific indices to use from data provider
*/
@Factory(
dataProvider = "factoryData",
dataProviderClass = FactoryDataProvider.class,
enabled = true,
indices = {0, 1, 2}
)
public Object[] createInstances() {
return new Object[] { new TestClass() };
}Usage Examples:
// Factory creating multiple instances
public class TestFactory {
@Factory
public Object[] createTests() {
return new Object[] {
new WebTest("Chrome"),
new WebTest("Firefox"),
new WebTest("Safari")
};
}
}
public class WebTest {
private String browser;
public WebTest(String browser) {
this.browser = browser;
}
@Test
public void testBrowser() {
System.out.println("Testing with " + browser);
}
}
// Factory with data provider
public class ParameterizedFactory {
@DataProvider
public Object[][] browsers() {
return new Object[][] {
{"Chrome"},
{"Firefox"},
{"Safari"}
};
}
@Factory(dataProvider = "browsers")
public Object[] createBrowserTests(String browser) {
return new Object[] { new BrowserTest(browser) };
}
}Annotations for parameter injection from testng.xml and dependency injection frameworks.
// Parameter injection from testng.xml
@Parameters({"username", "password"})
@Test
public void testLogin(String username, String password) { }
// Optional parameters (no error if missing)
@Parameters("optionalParam")
@Test
public void testOptional(@Optional("defaultValue") String param) { }
// Guice dependency injection
@Guice(modules = {TestModule.class})
public class GuiceTest {
@Inject
private UserService userService;
@Test
public void testWithInjection() {
// userService is injected by Guice
}
}Annotations for configuring listeners and custom test attributes.
// Listener configuration
@Listeners({TestListener.class, SuiteListener.class})
public class ListenerTest {
@Test
public void testWithListeners() { }
}
// Custom attributes
@Test
@CustomAttribute(name = "category", values = {"smoke"})
@CustomAttribute(name = "owner", values = {"john.doe"})
public void testWithAttributes() { }// Annotation interfaces (for reflection/programmatic access)
public interface Test {
String[] groups() default {};
String[] dependsOnMethods() default {};
String[] dependsOnGroups() default {};
boolean enabled() default true;
long timeOut() default 0L;
int invocationCount() default 1;
int threadPoolSize() default 0;
int successPercentage() default 100;
String dataProvider() default "";
Class<?> dataProviderClass() default Object.class;
Class<? extends Throwable>[] expectedExceptions() default {};
int priority() default 0;
String description() default "";
String suiteName() default "";
String testName() default "";
boolean singleThreaded() default false;
Class<? extends IRetryAnalyzer> retryAnalyzer() default IRetryAnalyzer.class;
}
public interface DataProvider {
String name() default "";
boolean parallel() default false;
int[] indices() default {};
boolean propagateFailureAsTestFailure() default false;
boolean cacheDataForTestRetries() default false;
Class<? extends IRetryDataProvider> retryUsing() default IRetryDataProvider.class;
}Install with Tessl CLI
npx tessl i tessl/maven-org-testng--testng