Allure is the reporting tool that turns TestNG XML output into interactive HTML reports with screenshots, steps, parameters, and environment metadata. For mobile suites, it shows which tests failed on which device/platform and what the app looked like at the moment of failure.
Adding Allure to Maven
<dependencies>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>2.25.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/1.9.21/aspectjweaver-1.9.21.jar"
</argLine>
<properties>
<property>
<name>listener</name>
<value>io.qameta.allure.testng.AllureTestNg</value>
</property>
</properties>
</configuration>
</plugin>
</plugins>
</build>Also add the AspectJ dependency:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.21</version>
<scope>test</scope>
</dependency>Annotating tests for Allure
import io.qameta.allure.*;
@Epic("Mobile Authentication")
@Feature("Login")
public class LoginTest extends BaseTest {
@Test
@Story("Valid credentials login")
@Severity(SeverityLevel.BLOCKER)
@Description("Verify that a registered user can log in with valid credentials and land on the home screen")
public void loginWithValidCredentials() {
// ...
}
@Test
@Story("Invalid password")
@Severity(SeverityLevel.NORMAL)
public void loginWithWrongPassword() {
// ...
}
}The Epic → Feature → Story hierarchy appears in Allure's left-hand navigation tree.
Adding steps to the report
@Step annotates methods in page objects or test helpers to show them as named steps in the report:
import io.qameta.allure.Step;
public class LoginPage extends BasePage {
@Step("Enter email: {email}")
public void enterEmail(String email) {
waitForClickable(EMAIL_FIELD).sendKeys(email);
}
@Step("Enter password")
public void enterPassword(String password) {
waitForClickable(PASSWORD_FIELD).sendKeys(password);
}
@Step("Tap Login button")
public HomePage tapLogin() {
waitForClickable(LOGIN_BUTTON).click();
return new HomePage(driver);
}
}The {email} in @Step("Enter email: {email}") is replaced with the actual parameter value in the report. Avoid using {password} in step names — it would appear in plain text in the report.
Attaching screenshots to test steps
import io.qameta.allure.Allure;
import java.io.ByteArrayInputStream;
public static void attachScreenshot(AppiumDriver driver, String name) {
byte[] screenshot = driver.getScreenshotAs(OutputType.BYTES);
Allure.addAttachment(name, "image/png",
new ByteArrayInputStream(screenshot), "png");
}
// In the listener's onTestFailure:
@Override
public void onTestFailure(ITestResult result) {
AppiumDriver driver = DriverManager.getDriver();
if (driver != null) {
AllureUtils.attachScreenshot(driver, "Screenshot at failure");
}
}Adding platform info to the report
The Allure Environment section shows the device and platform used for each test run. Create src/test/resources/allure.properties:
allure.results.directory=target/allure-resultsThen write environment data programmatically at suite start:
import io.qameta.allure.Allure;
@BeforeSuite
public void writeAllureEnvironment() {
Properties env = new Properties();
env.setProperty("Platform", System.getProperty("platform", "Android"));
env.setProperty("Device", System.getProperty("deviceName", "emulator-5554"));
env.setProperty("App Version", readAppVersion());
try (FileOutputStream fos = new FileOutputStream(
"target/allure-results/environment.properties")) {
env.store(fos, "Test Environment");
} catch (IOException e) {
System.err.println("Could not write Allure environment: " + e.getMessage());
}
}Adding parameters per test method
For data-driven tests, attach the parameter set to each test result:
@BeforeMethod
public void attachTestParameters(Object[] params) {
if (params.length > 0 && params[0] instanceof LoginTestData data) {
Allure.parameter("Email", data.email());
Allure.parameter("Expect success", data.expectSuccess());
}
}Each parameter appears as a labelled value in the test detail view.
Generating and serving the report
# Run tests (results go to target/allure-results)
mvn test -DsuiteFile=testng.xml
# Generate HTML report
mvn allure:report
# Or serve it locally on port 8080
mvn allure:serveIn CI, archive target/allure-results as a build artifact and run allure generate in a post-build step. Most CI tools have Allure plugins that display the report inline:
# GitHub Actions
- name: Generate Allure Report
if: always()
run: mvn allure:report
- name: Upload Allure Results
uses: actions/upload-artifact@v4
if: always()
with:
name: allure-results
path: target/allure-results