Allure annotations are like labels on a filing cabinet. Without them, your report is a flat list of test names. With them, your report is organized by business area, feature, user story, severity, and linked to JIRA tickets. This is what makes Allure powerful — not just the pretty graphs, but the organization.
Think of it like folders on your desktop. Epic is the top-level folder (Banking Portal). Feature is a sub-folder (User Authentication). Story is a file inside (Valid Login). In the Allure Behaviors tab, stakeholders can drill down from Epic to Feature to Story to find exactly what is tested and what is broken.
| Annotation | Level | Purpose | Example |
|---|---|---|---|
| @Epic | Class | Top-level business grouping | @Epic("Banking Portal") |
| @Feature | Class | Feature under an epic | @Feature("Fund Transfer") |
| @Story | Method | User story under a feature | @Story("Transfer to Savings") |
| @Description | Method | Detailed test description | @Description("Verify transfer of $500...") |
| @Severity | Method | Priority: BLOCKER to TRIVIAL | @Severity(SeverityLevel.CRITICAL) |
| @Step | Method | Reportable action step | @Step("Click login button") |
| @Link | Method | External link | @Link(name="Docs", url="...") |
| @Issue | Method | Bug tracker link | @Issue("BUG-567") |
| @TmsLink | Method | Test management link | @TmsLink("TC-789") |
| @Owner | Method | Test owner | @Owner("shivam") |
| @Attachment | Method | Attach file to report | Returns byte[] or String |
import io.qameta.allure.*;
import org.testng.Assert;
import org.testng.annotations.Test;
@Epic("Banking Portal")
@Feature("User Authentication")
public class LoginTests extends BaseTest {
@Test
@Story("Valid Login")
@Description("Verify that a registered user can log in with valid "
+ "credentials and land on the dashboard page")
@Severity(SeverityLevel.BLOCKER)
@Owner("shivam")
@Link(name = "Login Spec", url = "https://wiki.example.com/login-spec")
public void testValidLogin() {
LoginPage loginPage = new LoginPage(driver);
DashboardPage dashboard = loginPage.loginAs("testuser", "Pass@123");
Assert.assertTrue(dashboard.isWelcomeMessageDisplayed(),
"Welcome message should be visible after login");
Assert.assertEquals(dashboard.getLoggedInUsername(), "testuser",
"Logged in username should match");
}
@Test
@Story("Invalid Login")
@Description("Verify that invalid credentials show error and do not "
+ "navigate away from login page")
@Severity(SeverityLevel.CRITICAL)
@Issue("BUG-1023")
public void testInvalidCredentials() {
LoginPage loginPage = new LoginPage(driver);
loginPage.loginAs("wrong", "wrong");
Assert.assertTrue(loginPage.isErrorMessageDisplayed(),
"Error message should appear for invalid credentials");
Assert.assertEquals(loginPage.getErrorMessageText(),
"Invalid username or password");
}
@Test
@Story("Empty Fields")
@Description("Verify that submitting empty login form shows "
+ "validation messages")
@Severity(SeverityLevel.NORMAL)
public void testEmptyLoginFields() {
LoginPage loginPage = new LoginPage(driver);
loginPage.clickLoginButton();
Assert.assertTrue(loginPage.isUsernameValidationShown(),
"Username required validation should appear");
Assert.assertTrue(loginPage.isPasswordValidationShown(),
"Password required validation should appear");
}
@Test
@Story("Account Lockout")
@Description("Verify account locks after 3 consecutive failed attempts")
@Severity(SeverityLevel.CRITICAL)
@TmsLink("TC-AUTH-042")
public void testAccountLockout() {
LoginPage loginPage = new LoginPage(driver);
for (int i = 0; i < 3; i++) {
loginPage.loginAs("testuser", "wrongpass");
}
Assert.assertTrue(loginPage.isAccountLockedMessageDisplayed(),
"Account locked message should appear after 3 failed attempts");
}
}@Epic and @Feature go on the class. @Story, @Description, @Severity go on individual test methods. This keeps your class clean — the epic/feature applies to all tests in the class, while each test has its own story and severity.
Do not mark everything as CRITICAL or BLOCKER. If everything is critical, nothing is critical. Use severity honestly. In CI, some teams configure the pipeline to fail only on BLOCKER/CRITICAL failures and allow MINOR/TRIVIAL tests to fail without blocking the build.
Q: How do you organize tests in the Allure report?
A: I use the three-level BDD hierarchy: @Epic at the class level for the business domain (e.g., "Banking Portal"), @Feature for the module (e.g., "Fund Transfer"), and @Story at the method level for the specific user story (e.g., "Transfer Between Own Accounts"). This creates a drill-down view in the Behaviors tab where stakeholders can navigate from business area to feature to specific test cases. I also use @Severity to prioritize failures — BLOCKER for login/checkout, CRITICAL for core features, NORMAL for standard functionality.
Key Point: Annotations are not decoration — they organize your report from a random test list into a business-readable hierarchy.