Folha de Dicas Abrangente do TestNG
Instalação
| Plataforma/Ferramenta | Método de Instalação |
|---|
| 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 | Ajuda → Eclipse Marketplace → Pesquisar “TestNG” → Instalar |
| IntelliJ IDEA | Agrupado por padrão (ou File → Settings → Plugins → Marketplace → “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 |
Anotações Principais
| Anotação | Descrição |
|---|
@Test | Marca um método como um método de teste |
@Test(priority = 1) | Define a ordem de execução (números menores são executados primeiro) |
@Test(description = "...") | Adiciona texto descritivo para teste de relatório |
@Test(timeOut = 5000) | Falha no teste se a execução exceder o tempo limite (milissegundos) |
@Test(expectedExceptions = Exception.class) | Espera que uma exceção específica seja lançada |
@Test(enabled = false) | Desativa/pula o teste |
@Test(groups = {"smoke", "regression"}) | Atribui teste a um ou mais grupos |
@Test(dependsOnMethods = {"testMethod"}) | Executa após o método(s) especificado(s) ser(em) concluído(s) |
@Test(dependsOnGroups = {"smoke"}) | Executa após todos os testes no(s) grupo(s) especificado(s) |
@Test(alwaysRun = true) | Executa teste mesmo se dependências falharem |
@Test(invocationCount = 3) | Executa teste múltiplas vezes |
@Test(threadPoolSize = 5) | Executa múltiplas invocações em threads paralelos |
@BeforeMethod | Executes before each @Test method |
@AfterMethod | Executes after each @Test method |
@BeforeClass | Executa uma vez antes de qualquer método de teste na classe |
@AfterClass | Executa uma vez após todos os métodos de teste na classe |
@BeforeTest | Executes before any test method in <test> tag |
@AfterTest | Executes after all test methods in <test> tag |
@BeforeSuite | Executa uma vez antes de todos os testes na suíte |
@AfterSuite | Executa uma vez após todos os testes na suíte |
@BeforeGroups | Executa antes do primeiro método de teste do(s) grupo(s) especificado(s) |
@AfterGroups | Executa após o último método de teste do(s) grupo(s) especificado(s) |
@DataProvider | Fornece dados para testar métodos de parametrização |
@Parameters | Injects parameters from testng.xml into test methods |
@Factory | Cria instâncias de teste dinamicamente |
@Listeners | Anexa ouvintes personalizados à classe de teste |
Execução via Linha de Comando
| Comando | Descrição |
|---|
java -cp "classes:lib/*" org.testng.TestNG testng.xml | Executar testes usando arquivo de suite XML |
java -cp "classes:lib/*" org.testng.TestNG -testclass com.example.MyTest | Executar classe de teste específica |
java -cp "classes:lib/*" org.testng.TestNG -testclass Test1,Test2 | Execute várias classes de teste (separadas por vírgula) |
java -cp "classes:lib/*" org.testng.TestNG -groups smoke testng.xml | Executar testes de grupo(s) específico(s) |
java -cp "classes:lib/*" org.testng.TestNG -excludegroups slow testng.xml | Excluir grupo(s) específico(s) da execução |
java -cp "classes:lib/*" org.testng.TestNG -d test-output testng.xml | Especificar diretório de saída para relatórios |
java -cp "classes:lib/*" org.testng.TestNG -parallel methods -threadcount 5 | Execute testes em paralelo com contagem de threads |
java -cp "classes:lib/*" org.testng.TestNG -verbose 10 testng.xml | Definir nível de verbosidade (0-10, maior = mais detalhes) |
java -cp "classes:lib/*" org.testng.TestNG -methods MyTest.test1,MyTest.test2 | Executar métodos de teste específicos |
java -cp "classes:lib/*" org.testng.TestNG -suitename "MySuite" -testname "MyTest" | Substituir nomes de suíte e teste |
java -cp "classes:lib/*" org.testng.TestNG -reporter org.testng.reporters.EmailableReporter | Use um reporter específico |
java -cp "classes:lib/*" org.testng.TestNG -listener com.example.MyListener | Adicionar listener personalizado |
Comandos Maven
| Comando | Descrição |
|---|
mvn test | Executar todos os testes |
mvn test -Dtest=MyTestClass | Executar classe de teste específica |
mvn test -Dtest=MyTestClass#testMethod | Executar método de teste específico |
mvn test -Dtest=MyTestClass#test* | Executar métodos de teste correspondentes ao padrão |
mvn test -DsuiteXmlFile=smoke-tests.xml | Executar arquivo XML de suite específico |
mvn test -Dgroups=smoke,regression | Executar grupos de testes específicos |
mvn test -DexcludedGroups=slow | Excluir grupos de teste específicos |
mvn test -Denvironment=staging -Dbrowser=chrome | Passar propriedades do sistema para testes |
mvn test -DskipTests | Ignorar execução de teste |
mvn test -Dmaven.test.failure.ignore=true | Continue build mesmo se os testes falharem |
mvn test -Dparallel=methods -DthreadCount=4 | Executar testes em paralelo |
mvn clean test | Limpar builds anteriores e executar testes |
mvn test -X | Executar testes com saída de depuração |
mvn surefire-report:report | Gerar relatório de teste HTML |
Comandos Gradle
| Comando | Descrição |
|---|
gradle test | Executar todos os testes |
gradle test --tests MyTestClass | Executar classe de teste específica |
gradle test --tests MyTestClass.testMethod | Executar método de teste específico |
gradle test --tests *IntegrationTest | Executar testes correspondentes ao padrão |
gradle test --tests MyTestClass --tests OtherTest | Executar múltiplas classes de teste |
gradle test -Denvironment=staging | Passar propriedades do sistema |
gradle clean test | Limpar e executar testes |
gradle test --info | Executar com registro detalhado |
gradle test --debug | Executar com registro de log em nível de depuração |
gradle test --rerun-tasks | Forçar execução novamente mesmo se estiver atualizado |
gradle test --continue | Continuar execução após falhas de teste |
gradle test --fail-fast | Parar execução no primeiro erro de teste |
Métodos de Asserção
| Método | Descrição |
|---|
Assert.assertEquals(actual, expected) | Verificar se dois valores são iguais |
Assert.assertEquals(actual, expected, "message") | Afirmar com mensagem de falha personalizada |
Assert.assertNotEquals(actual, expected) | Verificar se dois valores não são iguais |
Assert.assertTrue(condition) | Verificar se a condição é verdadeira |
Assert.assertFalse(condition) | Verificar condição é falso |
Assert.assertNull(object) | Verificar se objeto é nulo |
Assert.assertNotNull(object) | Verifique se o objeto não é nulo |
Assert.assertSame(actual, expected) | Verificar referência do mesmo objeto |
Assert.assertNotSame(actual, expected) | Verificar diferentes referências de objetos |
Assert.fail("message") | Falhar explicitamente um teste |
Assert.assertThrows(Exception.class, () -> {...}) | Verificar se a exceção é lançada |
Assert.expectThrows(Exception.class, () -> {...}) | Igual a assertThrows (alias) |
Provedores de Dados
| Padrão | Descrição |
|---|
@DataProvider(name = "testData") | Definir um método de provedor de dados |
@Test(dataProvider = "testData") | Usar provedor de dados no teste |
@DataProvider(parallel = true) | Executar iterações de provedor de dados em paralelo |
Object[][] dataProvider() | Retornar array 2D de dados de teste |
Iterator<Object[]> dataProvider() | Retornar iterador para grandes conjuntos de dados |
@DataProvider(indices = {0, 2, 4}) | Executar apenas índices de conjunto de dados específicos |
Exemplo de Provedor de Dados
@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);
}
Configuração XML do TestNG
Configuração Básica de Suite
<?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>
Configuração de Execução Paralela
<!-- 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 -->
Configuração do Plugin 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>
Configuração de Teste 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"
}
}
Casos de Uso Comuns
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();
}
}
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();
}
}
<?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();
}
}
}
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");
}
}
Caso de Uso 5: Listeners Personalizados e Relatórios
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);
}
}
Melhores Práticas
- Use nomes de teste significativos: Nomeie os testes de forma clara para descrever o que eles verificam (por exemplo,
testUserCanLoginWithValidCredentialsem vez de
Note: For items 1-20 where no specific text was provided, I’ve translated the headings and maintained the structure. If you have specific text for those items, please provide them and I’ll translate accordingly.test1- Aproveite grupos de forma eficaz: Organize testes em grupos lógicos (smoke, regression, api, ui) para executar subconjuntos de testes com base no contexto e economizar tempo de execução
-
Implemente configuração e desmontagem adequadas: Use @BeforeMethod/@AfterMethodpara configuração de nível de teste e @BeforeClass/@AfterClasspara operações caras como conexões de banco de dados
-
Torne os testes independentes: Cada teste deve ser autossuficiente e não depender da ordem de execução ou estado compartilhado. Use dependsOnMethodscom parcimônia e apenas quando existir dependência lógica
-
Use DataProviders para dados de teste: Separe os dados de teste de
Would you like me to complete the remaining placeholders or provide the full context for translation?