À medida que o projeto cresce, manter os testes organizados e manuteníveis torna-se essencial. Esta aula apresenta boas práticas de organização para projetos Appium de médio e grande porte.
src/test/
├── java/
│ ├── base/
│ │ ├── BaseTest.java # Setup/Teardown do driver
│ │ └── BasePage.java # Métodos comuns a todas as páginas
│ ├── pages/
│ │ ├── LoginPage.java
│ │ ├── HomePage.java
│ │ ├── PerfilPage.java
│ │ └── CheckoutPage.java
│ ├── tests/
│ │ ├── LoginTest.java
│ │ ├── HomeTest.java
│ │ └── CheckoutTest.java
│ └── utils/
│ ├── DriverFactory.java # Cria o driver conforme a plataforma
│ ├── WaitHelper.java # Métodos de espera
│ ├── ScreenshotHelper.java # Captura de tela em falhas
│ └── TestDataHelper.java # Geração de dados de teste
└── resources/
├── apps/
│ ├── meuapp.apk
│ └── meuapp.app
├── testdata/
│ └── usuarios.json
├── config.properties
└── testng.xml
Centralize métodos comuns a todas as Page Objects:
package base;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public abstract class BasePage {
protected final AndroidDriver driver;
protected final WebDriverWait wait;
protected BasePage(AndroidDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
}
protected WebElement esperarVisivel(By locator) {
return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
protected WebElement esperarClicavel(By locator) {
return wait.until(ExpectedConditions.elementToBeClickable(locator));
}
protected void clicar(By locator) {
esperarClicavel(locator).click();
}
protected void digitar(By locator, String texto) {
WebElement campo = esperarVisivel(locator);
campo.clear();
campo.sendKeys(texto);
}
protected String obterTexto(By locator) {
return esperarVisivel(locator).getText();
}
}Centralize a criação de drivers para suportar múltiplas plataformas:
package utils;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.options.XCUITestOptions;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
public class DriverFactory {
public static AppiumDriver createDriver(Properties config) throws MalformedURLException {
String plataforma = config.getProperty("platform");
if ("android".equalsIgnoreCase(plataforma)) {
return createAndroidDriver(config);
} else if ("ios".equalsIgnoreCase(plataforma)) {
return createIOSDriver(config);
}
throw new IllegalArgumentException("Plataforma não suportada: " + plataforma);
}
private static AndroidDriver createAndroidDriver(Properties config) throws MalformedURLException {
UiAutomator2Options options = new UiAutomator2Options();
options.setDeviceName(config.getProperty("android.device"));
options.setApp(config.getProperty("android.app"));
options.setAutoGrantPermissions(true);
return new AndroidDriver(new URL(config.getProperty("appium.url")), options);
}
private static IOSDriver createIOSDriver(Properties config) throws MalformedURLException {
XCUITestOptions options = new XCUITestOptions();
options.setDeviceName(config.getProperty("ios.device"));
options.setApp(config.getProperty("ios.app"));
options.setAutoAcceptAlerts(true);
return new IOSDriver(new URL(config.getProperty("appium.url")), options);
}
}Capture screenshots automaticamente quando um teste falhar:
package utils;
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.OutputType;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ScreenshotHelper {
public static void capturar(AppiumDriver driver, String nomeDoTeste) {
try {
String timestamp = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
String caminho = "target/screenshots/" + nomeDoTeste + "_" + timestamp + ".png";
File screenshot = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot, new File(caminho));
System.out.println("Screenshot salva em: " + caminho);
} catch (Exception e) {
System.err.println("Falha ao capturar screenshot: " + e.getMessage());
}
}
}Use no @AfterMethod:
@AfterMethod
public void tearDown(ITestResult result) {
if (result.getStatus() == ITestResult.FAILURE) {
ScreenshotHelper.capturar(driver, result.getName());
}
driver.quit();
}Organize os testes em grupos para execução seletiva:
@Test(groups = {"smoke", "login"})
public void loginComSucesso() { ... }
@Test(groups = {"regressao", "login"})
public void loginComSenhaErrada() { ... }Execute apenas o grupo smoke:
<!-- testng.xml -->
<suite name="Suite">
<test name="Smoke Tests">
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<classes>
<class name="tests.LoginTest"/>
</classes>
</test>
</suite>- Mantenha cada
@Testindependente — não assuma que outro teste rodou antes - Use
@BeforeMethodpara estado limpo: reinstale ou resete o app quando necessário - Capture screenshots em falhas para diagnóstico mais fácil
- Use grupos (
smoke,regressao) para facilitar a execução seletiva em CI/CD
Ir para: Testes Paralelos