Popular Searches
Popular Course Categories
Popular Courses

Test Annotations

TestNG / PyTest

<div class="selenium-notes">

<h1>Test Annotations in TestNG</h1>

<p>TestNG annotations are special Java annotations used to define, control, organize, and manage the execution lifecycle of automated test cases. In Selenium automation, TestNG annotations help determine when browser setup should happen, when test methods should execute, and when cleanup operations should be performed.</p>

<p>TestNG provides annotations for suite-level, test-level, class-level, method-level, and group-level configuration. These annotations help create reusable and maintainable Selenium automation frameworks by separating setup, test execution, validation, and cleanup responsibilities.</p>

<p><strong>Course Resource:</strong> <a href="https://www.justacademy.co/course-detail/selenium-training" target="_blank" rel="noopener noreferrer">Selenium Training</a> | <a href="https://www.justacademy.co/register-for-course-demo" target="_blank" rel="noopener noreferrer">Register for Course Demo</a></p>

<hr>

<h2>1. What are TestNG Annotations?</h2>

<p>TestNG annotations are Java annotations beginning with the <strong>@</strong> symbol that provide instructions to the TestNG framework about how and when a particular method should be executed.</p>

<p>For example, <strong>@Test</strong> identifies a method as a test method, <strong>@BeforeMethod</strong> performs setup before each test method, and <strong>@AfterMethod</strong> performs cleanup after each test method.</p>

<pre><code>TestNG Annotations

        |

        +-- @BeforeSuite

        |

        +-- @BeforeTest

        |

        +-- @BeforeClass

        |

        +-- @BeforeMethod

        |

        +-- @Test

        |

        +-- @AfterMethod

        |

        +-- @AfterClass

        |

        +-- @AfterTest

        |

        +-- @AfterSuite</code></pre>

<hr>

<h2>2. Why are TestNG Annotations Important?</h2>

<p>In a Selenium automation project, tests usually require several activities before and after execution. A browser may need to be launched, an application opened, test data prepared, screenshots captured, reports generated, and the browser closed after execution.</p>

<p>Without annotations, these operations would have to be manually controlled inside every test method. TestNG annotations provide a structured lifecycle that makes automation code easier to organize, reuse, maintain, and scale.</p>

<ul>

<li>Define test methods.</li>

<li>Perform test setup.</li>

<li>Perform test cleanup.</li>

<li>Initialize WebDriver.</li>

<li>Close WebDriver.</li>

<li>Prepare test data.</li>

<li>Configure test execution.</li>

<li>Organize test suites.</li>

<li>Group test cases.</li>

<li>Control execution behavior.</li>

<li>Support data-driven testing.</li>

<li>Support reusable framework architecture.</li>

<li>Help integrate testing with reporting and CI/CD.</li>

</ul>

<hr>

<h2>3. TestNG Annotation Categories</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Category</th><th>Annotations</th><th>Purpose</th></tr>

<tr><td>Test Annotation</td><td>@Test</td><td>Defines a test method</td></tr>

<tr><td>Suite Configuration</td><td>@BeforeSuite, @AfterSuite</td><td>Runs around the complete suite</td></tr>

<tr><td>Test Configuration</td><td>@BeforeTest, @AfterTest</td><td>Runs around a TestNG XML &lt;test&gt; section</td></tr>

<tr><td>Class Configuration</td><td>@BeforeClass, @AfterClass</td><td>Runs around test methods in a class</td></tr>

<tr><td>Method Configuration</td><td>@BeforeMethod, @AfterMethod</td><td>Runs before and after each test method</td></tr>

<tr><td>Group Configuration</td><td>@BeforeGroups, @AfterGroups</td><td>Runs around specified test groups</td></tr>

<tr><td>Data Configuration</td><td>@DataProvider</td><td>Supplies multiple data sets to tests</td></tr>

</table>

<hr>

<h2>4. @Test Annotation</h2>

<p>The <strong>@Test</strong> annotation is the primary TestNG annotation. It tells TestNG that a particular method should be treated as a test method.</p>

<pre><code>import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test

    public void loginTest() {

        System.out.println("Login test executed");

    }

}</code></pre>

<p>When TestNG executes this class, it identifies the method marked with <strong>@Test</strong> and executes it as a test case.</p>

<h3>Example with Selenium</h3>

<pre><code>import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.testng.Assert;

import org.testng.annotations.Test;

 

public class GoogleTest {

 

    @Test

    public void verifyGoogleTitle() {

        WebDriver driver = new ChromeDriver();

 

        driver.get("https://www.google.com");

 

        Assert.assertTrue(driver.getTitle().contains("Google"));

 

        driver.quit();

    }

}</code></pre>

<hr>

<h2>5. @BeforeSuite Annotation</h2>

<p><strong>@BeforeSuite</strong> executes before the tests belonging to a TestNG suite. It is intended for suite-level initialization activities.</p>

<p>It can be useful for initializing framework-level resources such as reporting, global configuration, test directories, or other resources that should be prepared once for the suite.</p>

<pre><code>import org.testng.annotations.BeforeSuite;

 

public class SuiteSetup {

 

    @BeforeSuite

    public void beforeSuite() {

        System.out.println("Suite setup executed");

    }

}</code></pre>

<h3>Common Use Cases</h3>

<ul>

<li>Initialize reporting.</li>

<li>Create report directories.</li>

<li>Load global configuration.</li>

<li>Prepare environment-level resources.</li>

<li>Initialize framework-level services.</li>

</ul>

<hr>

<h2>6. @AfterSuite Annotation</h2>

<p><strong>@AfterSuite</strong> executes after the tests in the relevant TestNG suite have completed.</p>

<pre><code>import org.testng.annotations.AfterSuite;

 

public class SuiteCleanup {

 

    @AfterSuite

    public void afterSuite() {

        System.out.println("Suite cleanup executed");

    }

}</code></pre>

<p>It can be used for final cleanup, report finalization, or releasing suite-level resources.</p>

<hr>

<h2>7. @BeforeTest Annotation</h2>

<p><strong>@BeforeTest</strong> executes before the TestNG XML <strong>&lt;test&gt;</strong> section associated with the configuration.</p>

<pre><code>import org.testng.annotations.BeforeTest;

 

public class TestSetup {

 

    @BeforeTest

    public void beforeTest() {

        System.out.println("Before Test executed");

    }

}</code></pre>

<p>A very important point is that <strong>@BeforeTest does not mean before every @Test method</strong>. The word "Test" here refers to the TestNG XML <strong>&lt;test&gt;</strong> configuration section.</p>

<hr>

<h2>8. @AfterTest Annotation</h2>

<p><strong>@AfterTest</strong> executes after the relevant TestNG XML <strong>&lt;test&gt;</strong> section has completed.</p>

<pre><code>import org.testng.annotations.AfterTest;

 

public class TestCleanup {

 

    @AfterTest

    public void afterTest() {

        System.out.println("After Test executed");

    }

}</code></pre>

<p>It can be used for cleanup activities associated with a TestNG XML test section.</p>

<hr>

<h2>9. @BeforeClass Annotation</h2>

<p><strong>@BeforeClass</strong> executes before the first test method in the current class.</p>

<pre><code>import org.testng.annotations.BeforeClass;

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @BeforeClass

    public void setupClass() {

        System.out.println("Class setup");

    }

 

    @Test

    public void loginTest() {

        System.out.println("Login test");

    }

 

    @Test

    public void forgotPasswordTest() {

        System.out.println("Forgot password test");

    }

}</code></pre>

<p><strong>@BeforeClass</strong> is intended for class-level initialization. It should not be confused with <strong>@BeforeMethod</strong>, which executes before every test method.</p>

<hr>

<h2>10. @AfterClass Annotation</h2>

<p><strong>@AfterClass</strong> executes after the test methods in the current class have completed.</p>

<pre><code>import org.testng.annotations.AfterClass;

 

public class LoginTest {

 

    @AfterClass

    public void cleanupClass() {

        System.out.println("Class cleanup");

    }

}</code></pre>

<p>It is useful when a resource needs to be released after class-level test execution.</p>

<hr>

<h2>11. @BeforeMethod Annotation</h2>

<p><strong>@BeforeMethod</strong> executes before each method annotated with <strong>@Test</strong> in the relevant class.</p>

<pre><code>import org.testng.annotations.BeforeMethod;

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @BeforeMethod

    public void setup() {

        System.out.println("Before every test");

    }

 

    @Test

    public void validLogin() {

        System.out.println("Valid login");

    }

 

    @Test

    public void invalidLogin() {

        System.out.println("Invalid login");

    }

}</code></pre>

<p>In Selenium projects, <strong>@BeforeMethod</strong> is frequently used to create a WebDriver instance, configure the browser, and open the application before every test.</p>

<hr>

<h2>12. @AfterMethod Annotation</h2>

<p><strong>@AfterMethod</strong> executes after each test method.</p>

<pre><code>import org.testng.annotations.AfterMethod;

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test

    public void loginTest() {

        System.out.println("Login test");

    }

 

    @AfterMethod

    public void cleanup() {

        System.out.println("After every test");

    }

}</code></pre>

<p>In Selenium automation, <strong>@AfterMethod</strong> is commonly used to capture failure evidence and close or quit the browser after every test.</p>

<hr>

<h2>13. @BeforeGroups Annotation</h2>

<p><strong>@BeforeGroups</strong> executes before the first test method belonging to the specified group or groups, subject to the selected suite and group configuration.</p>

<pre><code>import org.testng.annotations.BeforeGroups;

import org.testng.annotations.Test;

 

public class GroupTest {

 

    @BeforeGroups("smoke")

    public void setupSmokeTests() {

        System.out.println("Smoke group setup");

    }

 

    @Test(groups = "smoke")

    public void loginTest() {

        System.out.println("Login test");

    }

 

    @Test(groups = "smoke")

    public void homePageTest() {

        System.out.println("Home page test");

    }

}</code></pre>

<hr>

<h2>14. @AfterGroups Annotation</h2>

<p><strong>@AfterGroups</strong> executes after the specified group has completed, according to the applicable TestNG group configuration.</p>

<pre><code>import org.testng.annotations.AfterGroups;

import org.testng.annotations.Test;

 

public class GroupCleanupTest {

 

    @Test(groups = "regression")

    public void checkoutTest() {

        System.out.println("Checkout test");

    }

 

    @AfterGroups("regression")

    public void cleanupRegression() {

        System.out.println("Regression group cleanup");

    }

}</code></pre>

<hr>

<h2>15. Complete TestNG Annotation Lifecycle</h2>

<p>A simplified lifecycle can be represented as follows:</p>

<pre><code>@BeforeSuite

      |

      v

@BeforeTest

      |

      v

@BeforeClass

      |

      v

@BeforeMethod

      |

      v

@Test

      |

      v

@AfterMethod

      |

      v

@AfterClass

      |

      v

@AfterTest

      |

      v

@AfterSuite</code></pre>

<p>This is a simplified conceptual flow. Actual execution can vary depending on the suite structure, multiple XML &lt;test&gt; sections, classes, groups, inheritance, dependencies, and configuration methods.</p>

<hr>

<h2>16. Complete Annotation Example</h2>

<pre><code>import org.testng.annotations.*;

 

public class AnnotationExample {

 

    @BeforeSuite

    public void beforeSuite() {

        System.out.println("Before Suite");

    }

 

    @BeforeTest

    public void beforeTest() {

        System.out.println("Before Test");

    }

 

    @BeforeClass

    public void beforeClass() {

        System.out.println("Before Class");

    }

 

    @BeforeMethod

    public void beforeMethod() {

        System.out.println("Before Method");

    }

 

    @Test

    public void testLogin() {

        System.out.println("Login Test");

    }

 

    @Test

    public void testSearch() {

        System.out.println("Search Test");

    }

 

    @AfterMethod

    public void afterMethod() {

        System.out.println("After Method");

    }

 

    @AfterClass

    public void afterClass() {

        System.out.println("After Class");

    }

 

    @AfterTest

    public void afterTest() {

        System.out.println("After Test");

    }

 

    @AfterSuite

    public void afterSuite() {

        System.out.println("After Suite");

    }

}</code></pre>

<hr>

<h2>17. Execution Flow with Multiple Test Methods</h2>

<pre><code>@BeforeSuite

     |

     v

@BeforeTest

     |

     v

@BeforeClass

     |

     +----------------------+

     |                      |

     v                      v

@BeforeMethod          @BeforeMethod

     |                      |

     v                      v

@Test Login            @Test Search

     |                      |

     v                      v

@AfterMethod           @AfterMethod

     |                      |

     +----------+-----------+

                |

                v

          @AfterClass

                |

                v

           @AfterTest

                |

                v

           @AfterSuite</code></pre>

<hr>

<h2>18. TestNG Annotations with Selenium WebDriver</h2>

<p>Annotations become particularly useful when Selenium WebDriver is integrated with TestNG. Instead of creating and closing the browser separately inside every test, common setup and cleanup can be placed in configuration methods.</p>

<pre><code>import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.testng.annotations.*;

 

public class BaseTest {

 

    protected WebDriver driver;

 

    @BeforeMethod

    public void setUp() {

        driver = new ChromeDriver();

        driver.manage().window().maximize();

    }

 

    @AfterMethod(alwaysRun = true)

    public void tearDown() {

        if (driver != null) {

            driver.quit();

        }

    }

}</code></pre>

<h3>Test Class</h3>

<pre><code>import org.testng.Assert;

import org.testng.annotations.Test;

 

public class HomePageTest extends BaseTest {

 

    @Test

    public void verifyGoogleTitle() {

        driver.get("https://www.google.com");

 

        Assert.assertTrue(

            driver.getTitle().contains("Google")

        );

    }

 

    @Test

    public void verifyGoogleUrl() {

        driver.get("https://www.google.com");

 

        Assert.assertTrue(

            driver.getCurrentUrl().contains("google")

        );

    }

}</code></pre>

<p>Here, browser setup runs before each test and cleanup runs after each test.</p>

<hr>

<h2>19. Common @Test Annotation Attributes</h2>

<p>The <strong>@Test</strong> annotation provides several attributes that can control test behavior.</p>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Attribute</th><th>Purpose</th></tr>

<tr><td>priority</td><td>Defines relative execution priority among applicable tests</td></tr>

<tr><td>groups</td><td>Assigns a test to one or more groups</td></tr>

<tr><td>dependsOnMethods</td><td>Defines dependency on specific test methods</td></tr>

<tr><td>dependsOnGroups</td><td>Defines dependency on test groups</td></tr>

<tr><td>enabled</td><td>Enables or disables a test</td></tr>

<tr><td>dataProvider</td><td>Connects a test with a DataProvider</td></tr>

<tr><td>dataProviderClass</td><td>Specifies a class containing the DataProvider</td></tr>

<tr><td>timeOut</td><td>Defines the maximum allowed execution time</td></tr>

<tr><td>expectedExceptions</td><td>Specifies exception types expected from the test</td></tr>

<tr><td>description</td><td>Provides a description for the test</td></tr>

<tr><td>invocationCount</td><td>Runs a test method multiple times</td></tr>

<tr><td>invocationTimeOut</td><td>Limits the time allowed for repeated invocations</td></tr>

<tr><td>threadPoolSize</td><td>Controls the thread pool for repeated invocations when applicable</td></tr>

<tr><td>alwaysRun</td><td>Controls execution behavior in dependency scenarios</td></tr>

</table>

<hr>

<h2>20. @Test Priority</h2>

<p>The <strong>priority</strong> attribute can be used to specify relative execution order among applicable test methods.</p>

<pre><code>@Test(priority = 1)

public void loginTest() {

    System.out.println("Login");

}

 

@Test(priority = 2)

public void searchTest() {

    System.out.println("Search");

}

 

@Test(priority = 3)

public void logoutTest() {

    System.out.println("Logout");

}</code></pre>

<p>Lower priority values are generally scheduled before higher values. However, test cases should preferably remain independent rather than relying heavily on execution order.</p>

<hr>

<h2>21. @Test Groups</h2>

<p>The <strong>groups</strong> attribute allows test methods to be categorized.</p>

<pre><code>@Test(groups = "smoke")

public void loginTest() {

    System.out.println("Login");

}

 

@Test(groups = "regression")

public void checkoutTest() {

    System.out.println("Checkout");

}

 

@Test(groups = {"smoke", "regression"})

public void searchTest() {

    System.out.println("Search");

}</code></pre>

<p>Common groups include smoke, sanity, regression, functional, integration, and end-to-end.</p>

<hr>

<h2>22. @Test Enabled Attribute</h2>

<p>The <strong>enabled</strong> attribute can enable or disable a test method.</p>

<pre><code>@Test(enabled = true)

public void activeTest() {

    System.out.println("This test will execute");

}

 

@Test(enabled = false)

public void disabledTest() {

    System.out.println("This test will not execute");

}</code></pre>

<p>A disabled test should be reviewed periodically so that obsolete tests do not remain permanently excluded from the suite.</p>

<hr>

<h2>23. @Test Description Attribute</h2>

<p>The <strong>description</strong> attribute provides additional information about a test.</p>

<pre><code>@Test(description = "Verify successful user login")

public void loginTest() {

    System.out.println("Login test");

}</code></pre>

<p>Descriptions can improve test reports and help team members understand test intent.</p>

<hr>

<h2>24. Test Dependencies</h2>

<p>TestNG allows test methods to depend on other test methods using <strong>dependsOnMethods</strong>.</p>

<pre><code>@Test

public void loginTest() {

    System.out.println("Login successful");

}

 

@Test(dependsOnMethods = "loginTest")

public void checkoutTest() {

    System.out.println("Checkout test");

}</code></pre>

<p>If the dependency does not complete successfully, the dependent test can be skipped according to TestNG's dependency behavior.</p>

<p>Dependencies should be used when a genuine business or technical relationship exists. Excessive dependencies can make test suites harder to maintain and execute independently.</p>

<hr>

<h2>25. dependsOnGroups</h2>

<p>The <strong>dependsOnGroups</strong> attribute allows a test to depend on a group of tests.</p>

<pre><code>@Test(groups = "login")

public void loginTest() {

    System.out.println("Login");

}

 

@Test(groups = "login")

public void sessionTest() {

    System.out.println("Session validation");

}

 

@Test(dependsOnGroups = "login")

public void checkoutTest() {

    System.out.println("Checkout");

}</code></pre>

<hr>

<h2>26. Expected Exceptions</h2>

<p>The <strong>expectedExceptions</strong> attribute allows a test to declare the exception type it expects to receive.</p>

<pre><code>@Test(expectedExceptions = ArithmeticException.class)

public void divisionTest() {

    int result = 10 / 0;

}</code></pre>

<p>If the expected exception occurs, TestNG can treat the test according to the declared expectation. This is useful when the expected behavior of a test is an exception.</p>

<hr>

<h2>27. Test Timeout</h2>

<p>The <strong>timeOut</strong> attribute specifies the maximum time allowed for a test method.</p>

<pre><code>@Test(timeOut = 5000)

public void pageTest() {

    System.out.println("Test execution");

}</code></pre>

<p>For Selenium automation, synchronization should generally be handled with appropriate waits rather than using unnecessarily large test-level timeouts.</p>

<hr>

<h2>28. invocationCount Attribute</h2>

<p>The <strong>invocationCount</strong> attribute runs the same test method multiple times.</p>

<pre><code>@Test(invocationCount = 3)

public void repeatedTest() {

    System.out.println("Test executed");

}</code></pre>

<p>In this example, TestNG invokes the test method three times.</p>

<h3>Using invocationCount with threadPoolSize</h3>

<pre><code>@Test(invocationCount = 5, threadPoolSize = 2)

public void parallelInvocationTest() {

    System.out.println("Repeated test execution");

}</code></pre>

<p>When parallel invocations are used, shared resources such as WebDriver instances must be designed for thread safety and proper isolation.</p>

<hr>

<h2>29. DataProvider Annotation</h2>

<p><strong>@DataProvider</strong> supplies multiple sets of data to a test method.</p>

<pre><code>import org.testng.annotations.DataProvider;

import org.testng.annotations.Test;

 

public class LoginDataTest {

 

    @DataProvider(name = "loginData")

    public Object[][] loginData() {

        return new Object[][] {

            {"user1", "password1"},

            {"user2", "password2"},

            {"user3", "password3"}

        };

    }

 

    @Test(dataProvider = "loginData")

    public void loginTest(String username, String password) {

        System.out.println(username);

        System.out.println(password);

    }

}</code></pre>

<p>The test method is invoked for each data set supplied by the DataProvider.</p>

<hr>

<h2>30. DataProvider with Selenium</h2>

<p>DataProvider is useful for testing multiple usernames, passwords, search terms, product values, or other input combinations.</p>

<pre><code>@DataProvider(name = "users")

public Object[][] users() {

    return new Object[][] {

        {"user1", "pass1"},

        {"user2", "pass2"},

        {"user3", "pass3"}

    };

}

 

@Test(dataProvider = "users")

public void loginTest(String username, String password) {

 

    driver.get("https://example.com/login");

 

    driver.findElement(By.id("username"))

          .sendKeys(username);

 

    driver.findElement(By.id("password"))

          .sendKeys(password);

 

    driver.findElement(By.id("login"))

          .click();

}</code></pre>

<hr>

<h2>31. dataProviderClass Attribute</h2>

<p>The <strong>dataProviderClass</strong> attribute can be used when the DataProvider is located in a separate class.</p>

<h3>TestData.java</h3>

<pre><code>import org.testng.annotations.DataProvider;

 

public class TestData {

 

    @DataProvider(name = "loginData")

    public Object[][] loginData() {

        return new Object[][] {

            {"admin", "admin123"},

            {"user", "user123"}

        };

    }

}</code></pre>

<h3>LoginTest.java</h3>

<pre><code>import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test(

        dataProvider = "loginData",

        dataProviderClass = TestData.class

    )

    public void loginTest(String username, String password) {

        System.out.println(username + " : " + password);

    }

}</code></pre>

<hr>

<h2>32. Annotation Inheritance</h2>

<p>TestNG configuration methods can be defined in a base class and used by subclasses. This is especially useful for Selenium automation frameworks.</p>

<h3>BaseTest.java</h3>

<pre><code>import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.testng.annotations.AfterMethod;

import org.testng.annotations.BeforeMethod;

 

public class BaseTest {

 

    protected WebDriver driver;

 

    @BeforeMethod

    public void setUp() {

        driver = new ChromeDriver();

    }

 

    @AfterMethod(alwaysRun = true)

    public void tearDown() {

        if (driver != null) {

            driver.quit();

        }

    }

}</code></pre>

<h3>LoginTest.java</h3>

<pre><code>import org.testng.annotations.Test;

 

public class LoginTest extends BaseTest {

 

    @Test

    public void loginTest() {

        driver.get("https://example.com/login");

        System.out.println("Login test");

    }

}</code></pre>

<p>This approach prevents every test class from duplicating the same browser setup and cleanup code.</p>

<hr>

<h2>33. alwaysRun Attribute</h2>

<p>Configuration annotations support the <strong>alwaysRun</strong> attribute. It can be useful when important cleanup should still be attempted even when preceding test or configuration conditions would otherwise affect normal execution.</p>

<pre><code>@AfterMethod(alwaysRun = true)

public void tearDown() {

    if (driver != null) {

        driver.quit();

    }

}</code></pre>

<p>Using <strong>alwaysRun = true</strong> for critical cleanup can help reduce the chance of leaving WebDriver sessions or other resources open.</p>

<hr>

<h2>34. @BeforeTest vs @BeforeMethod</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Feature</th><th>@BeforeTest</th><th>@BeforeMethod</th></tr>

<tr><td>Scope</td><td>TestNG XML &lt;test&gt; section</td><td>Each @Test method</td></tr>

<tr><td>Frequency</td><td>Once for the applicable XML test configuration</td><td>Before every test method</td></tr>

<tr><td>Common Use</td><td>Test-section configuration</td><td>Per-test setup</td></tr>

<tr><td>Selenium Example</td><td>Prepare test-level environment</td><td>Start/reset WebDriver</td></tr>

</table>

<hr>

<h2>35. @BeforeClass vs @BeforeMethod</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Feature</th><th>@BeforeClass</th><th>@BeforeMethod</th></tr>

<tr><td>Execution</td><td>Before the first test method in a class</td><td>Before every test method</td></tr>

<tr><td>Frequency</td><td>Class-level</td><td>Method-level</td></tr>

<tr><td>Use Case</td><td>Class-level initialization</td><td>Fresh setup for every test</td></tr>

<tr><td>Selenium Example</td><td>Prepare class-level resource</td><td>Create or reset WebDriver</td></tr>

</table>

<hr>

<h2>36. @BeforeSuite vs @BeforeTest vs @BeforeClass vs @BeforeMethod</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Annotation</th><th>Scope</th><th>Typical Usage</th></tr>

<tr><td>@BeforeSuite</td><td>Entire suite</td><td>Global framework setup</td></tr>

<tr><td>@BeforeTest</td><td>XML &lt;test&gt;</td><td>Test-section setup</td></tr>

<tr><td>@BeforeClass</td><td>Class</td><td>Class-level initialization</td></tr>

<tr><td>@BeforeMethod</td><td>Test method</td><td>Per-test setup</td></tr>

</table>

<hr>

<h2>37. Configuration Annotations with Selenium</h2>

<p>A typical Selenium framework can organize its lifecycle using configuration annotations as follows:</p>

<pre><code>@BeforeSuite

    |

    +-- Initialize reporting

    |

@BeforeTest

    |

    +-- Load test-level configuration

    |

@BeforeClass

    |

    +-- Initialize class-level resources

    |

@BeforeMethod

    |

    +-- Start WebDriver

    +-- Configure browser

    +-- Open application

    |

@Test

    |

    +-- Execute Selenium test

    +-- Perform assertions

    |

@AfterMethod

    |

    +-- Capture failure evidence

    +-- Quit WebDriver

    |

@AfterClass

    |

    +-- Release class resources

    |

@AfterTest

    |

    +-- Test-level cleanup

    |

@AfterSuite

    |

    +-- Finalize reports</code></pre>

<hr>

<h2>38. TestNG Annotations with Page Object Model</h2>

<p>TestNG annotations are frequently combined with the Page Object Model in Selenium automation. Page classes contain page-specific actions and locators, while TestNG controls setup, execution, validation, and cleanup.</p>

<pre><code>Selenium Automation Framework

          |

          +-- TestNG

          |     |

          |     +-- @BeforeMethod

          |     +-- @Test

          |     +-- @AfterMethod

          |

          +-- Page Objects

          |     |

          |     +-- LoginPage

          |     +-- HomePage

          |

          +-- WebDriver

          |

          +-- Utilities

          |

          +-- Reports</code></pre>

<hr>

<h2>39. Practical Login Automation Using Annotations</h2>

<h3>BaseTest.java</h3>

<pre><code>import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.testng.annotations.AfterMethod;

import org.testng.annotations.BeforeMethod;

 

public class BaseTest {

 

    protected WebDriver driver;

 

    @BeforeMethod

    public void setUp() {

        driver = new ChromeDriver();

        driver.manage().window().maximize();

        driver.get("https://example.com/login");

    }

 

    @AfterMethod(alwaysRun = true)

    public void tearDown() {

        if (driver != null) {

            driver.quit();

        }

    }

}</code></pre>

<h3>LoginTest.java</h3>

<pre><code>import org.openqa.selenium.By;

import org.testng.Assert;

import org.testng.annotations.Test;

 

public class LoginTest extends BaseTest {

 

    @Test

    public void validLoginTest() {

 

        driver.findElement(By.id("username"))

              .sendKeys("admin");

 

        driver.findElement(By.id("password"))

              .sendKeys("admin123");

 

        driver.findElement(By.id("login"))

              .click();

 

        Assert.assertTrue(

            driver.getCurrentUrl().contains("dashboard")

        );

    }

}</code></pre>

<h3>Execution Flow</h3>

<pre><code>@BeforeMethod

      |

      v

Start Browser

      |

      v

Open Login Page

      |

      v

@Test

      |

      v

Enter Username

      |

      v

Enter Password

      |

      v

Click Login

      |

      v

Assertion

      |

      v

@AfterMethod

      |

      v

Quit Browser</code></pre>

<hr>

<h2>40. Multiple Tests Using the Same Annotations</h2>

<pre><code>public class LoginTest extends BaseTest {

 

    @Test

    public void validLogin() {

        System.out.println("Valid Login");

    }

 

    @Test

    public void invalidLogin() {

        System.out.println("Invalid Login");

    }

 

    @Test

    public void forgotPassword() {

        System.out.println("Forgot Password");

    }

}</code></pre>

<p>With <strong>@BeforeMethod</strong> and <strong>@AfterMethod</strong> in the base class, each test can receive its own setup and cleanup cycle.</p>

<hr>

<h2>41. testng.xml with Annotations</h2>

<p>TestNG annotations work together with the suite configuration defined in <strong>testng.xml</strong>.</p>

<pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;

&lt;!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd"&gt;

 

&lt;suite name="Selenium Suite"&gt;

 

    &lt;test name="Login Tests"&gt;

        &lt;classes&gt;

            &lt;class name="LoginTest"/&gt;

        &lt;/classes&gt;

    &lt;/test&gt;

 

&lt;/suite&gt;</code></pre>

<p>The XML file defines the suite and test structure, while annotations define the behavior of test and configuration methods.</p>

<hr>

<h2>42. Annotation Execution Example with testng.xml</h2>

<pre><code>testng.xml

     |

     v

@BeforeSuite

     |

     v

@BeforeTest

     |

     v

@BeforeClass

     |

     v

@BeforeMethod

     |

     v

@Test

     |

     v

@AfterMethod

     |

     v

@AfterClass

     |

     v

@AfterTest

     |

     v

@AfterSuite</code></pre>

<hr>

<h2>43. Common Mistakes with TestNG Annotations</h2>

<h3>Mistake 1: Forgetting @Test</h3>

<pre><code>public void loginTest() {

    System.out.println("Login");

}</code></pre>

<p>Without <strong>@Test</strong>, the method is not identified as a normal TestNG test method.</p>

<h3>Correct</h3>

<pre><code>@Test

public void loginTest() {

    System.out.println("Login");

}</code></pre>

<h3>Mistake 2: Using @BeforeClass When Per-Test Setup is Required</h3>

<p>If the browser or test data must be reset before every test, <strong>@BeforeMethod</strong> is generally more appropriate than <strong>@BeforeClass</strong>.</p>

<h3>Mistake 3: Forgetting Browser Cleanup</h3>

<pre><code>@AfterMethod(alwaysRun = true)

public void tearDown() {

    if (driver != null) {

        driver.quit();

    }

}</code></pre>

<p>Not closing WebDriver sessions can consume system resources and create problems during large test executions.</p>

<h3>Mistake 4: Excessive Use of Priorities</h3>

<p>Using priority to create a large chain of dependent tests can make the suite fragile. Tests should remain independent wherever practical.</p>

<h3>Mistake 5: Confusing @BeforeTest with @BeforeMethod</h3>

<p><strong>@BeforeTest</strong> relates to the TestNG XML <strong>&lt;test&gt;</strong> configuration, whereas <strong>@BeforeMethod</strong> executes before each test method.</p>

<h3>Mistake 6: Sharing a WebDriver Unsafely in Parallel Execution</h3>

<p>When tests execute in parallel, sharing one WebDriver instance between threads can cause interference. WebDriver ownership should be isolated appropriately for the chosen parallel execution strategy.</p>

<hr>

<h2>44. Best Practices for TestNG Annotations</h2>

<ul>

<li>Use <strong>@BeforeSuite</strong> for suite-level initialization.</li>

<li>Use <strong>@AfterSuite</strong> for suite-level cleanup.</li>

<li>Use <strong>@BeforeTest</strong> for XML test-section configuration.</li>

<li>Use <strong>@AfterTest</strong> for XML test-section cleanup.</li>

<li>Use <strong>@BeforeClass</strong> for class-level initialization.</li>

<li>Use <strong>@AfterClass</strong> for class-level cleanup.</li>

<li>Use <strong>@BeforeMethod</strong> for setup required before every test.</li>

<li>Use <strong>@AfterMethod</strong> for cleanup required after every test.</li>

<li>Use <strong>alwaysRun = true</strong> where critical cleanup should still be attempted.</li>

<li>Keep test methods independent wherever practical.</li>

<li>Use meaningful test method names.</li>

<li>Use groups to organize execution categories.</li>

<li>Use DataProvider for data-driven testing.</li>

<li>Avoid unnecessary test dependencies.</li>

<li>Keep Selenium setup and test logic properly separated.</li>

<li>Use appropriate waits instead of arbitrary sleeps.</li>

<li>Ensure WebDriver instances are properly isolated during parallel execution.</li>

</ul>

<hr>

<h2>45. Test Annotations in Automation Framework Architecture</h2>

<pre><code>                Automation Framework

                         |

          +--------------+--------------+

          |              |              |

       TestNG         Selenium        Maven

          |

   +------+-------+

   |              |

Annotations    Assertions

   |

   +-- @BeforeSuite

   +-- @BeforeTest

   +-- @BeforeClass

   +-- @BeforeMethod

   +-- @Test

   +-- @AfterMethod

   +-- @AfterClass

   +-- @AfterTest

   +-- @AfterSuite

          |

          v

     Test Execution

          |

          v

       Reports

          |

          v

        CI/CD</code></pre>

<hr>

<h2>46. TestNG Annotations vs Normal Java Methods</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Normal Java Method</th><th>TestNG Annotated Method</th></tr>

<tr><td>Does not automatically belong to the TestNG lifecycle</td><td>Can participate in the TestNG lifecycle</td></tr>

<tr><td>Requires normal Java invocation</td><td>TestNG can invoke it according to configuration</td></tr>

<tr><td>No built-in TestNG test role</td><td>Can act as a test or configuration method</td></tr>

<tr><td>No TestNG execution metadata</td><td>Can use TestNG attributes</td></tr>

</table>

<hr>

<h2>47. Important TestNG Annotation Comparison</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Annotation</th><th>Runs</th><th>Common Selenium Usage</th></tr>

<tr><td>@BeforeSuite</td><td>Before the suite</td><td>Initialize framework/reporting resources</td></tr>

<tr><td>@AfterSuite</td><td>After the suite</td><td>Finalize reports/resources</td></tr>

<tr><td>@BeforeTest</td><td>Before XML &lt;test&gt;</td><td>Test-level setup</td></tr>

<tr><td>@AfterTest</td><td>After XML &lt;test&gt;</td><td>Test-level cleanup</td></tr>

<tr><td>@BeforeClass</td><td>Before first test in class</td><td>Class-level initialization</td></tr>

<tr><td>@AfterClass</td><td>After class tests</td><td>Class-level cleanup</td></tr>

<tr><td>@BeforeMethod</td><td>Before each @Test</td><td>Start/reset WebDriver</td></tr>

<tr><td>@AfterMethod</td><td>After each @Test</td><td>Screenshot/quit browser</td></tr>

<tr><td>@BeforeGroups</td><td>Before specified groups</td><td>Group-specific setup</td></tr>

<tr><td>@AfterGroups</td><td>After specified groups</td><td>Group-specific cleanup</td></tr>

<tr><td>@Test</td><td>Test execution</td><td>Execute Selenium scenario</td></tr>

<tr><td>@DataProvider</td><td>Provides test data</td><td>Data-driven Selenium tests</td></tr>

</table>

<hr>

<h2>48. Real-World Selenium TestNG Flow</h2>

<pre><code>Developer

   |

   v

TestNG Test Class

   |

   v

@BeforeSuite

   |

   v

@BeforeTest

   |

   v

@BeforeClass

   |

   v

@BeforeMethod

   |

   +-- Start Browser

   +-- Configure Browser

   +-- Open Application

   |

   v

@Test

   |

   +-- Locate Elements

   +-- Perform Actions

   +-- Validate Results

   |

   v

@AfterMethod

   |

   +-- Capture Screenshot if Required

   +-- Quit Browser

   |

   v

@AfterClass

   |

   v

@AfterTest

   |

   v

@AfterSuite

   |

   v

Test Report</code></pre>

<hr>

<h2>49. Advantages of TestNG Annotations</h2>

<ul>

<li>Provide a structured test lifecycle.</li>

<li>Reduce duplicate setup and cleanup code.</li>

<li>Improve test organization.</li>

<li>Make Selenium browser setup reusable.</li>

<li>Support suite-level and class-level configuration.</li>

<li>Support method-level setup and cleanup.</li>

<li>Support grouping and parameterization.</li>

<li>Work effectively with Page Object Model.</li>

<li>Help build maintainable automation frameworks.</li>

<li>Integrate effectively with Maven and CI/CD workflows.</li>

</ul>

<hr>

<h2>50. Interview Questions on TestNG Annotations</h2>

<h3>Q1. What are TestNG annotations?</h3>

<p>TestNG annotations are Java annotations used by the TestNG framework to define test methods and control different stages of test execution.</p>

<h3>Q2. What is the most important TestNG annotation?</h3>

<p><strong>@Test</strong> is the primary annotation used to identify a method as a TestNG test method.</p>

<h3>Q3. What is @BeforeMethod?</h3>

<p><strong>@BeforeMethod</strong> executes before each applicable test method.</p>

<h3>Q4. What is @AfterMethod?</h3>

<p><strong>@AfterMethod</strong> executes after each applicable test method and is commonly used for cleanup.</p>

<h3>Q5. What is the difference between @BeforeClass and @BeforeMethod?</h3>

<p><strong>@BeforeClass</strong> is used for setup before the first test method in a class, whereas <strong>@BeforeMethod</strong> runs before each test method.</p>

<h3>Q6. What is the difference between @BeforeSuite and @BeforeTest?</h3>

<p><strong>@BeforeSuite</strong> runs before the relevant suite, while <strong>@BeforeTest</strong> runs in relation to the TestNG XML <strong>&lt;test&gt;</strong> section.</p>

<h3>Q7. What is @AfterSuite?</h3>

<p><strong>@AfterSuite</strong> executes after the tests in the relevant suite have completed.</p>

<h3>Q8. What is @BeforeGroups?</h3>

<p><strong>@BeforeGroups</strong> executes before the first applicable test method belonging to the specified group or groups.</p>

<h3>Q9. Can TestNG configuration annotations be inherited?</h3>

<p>Yes. Configuration methods can be defined in base classes and used by subclasses, which is common in Selenium automation frameworks.</p>

<h3>Q10. Why is @BeforeMethod commonly used in Selenium?</h3>

<p>It is commonly used to perform setup before each test, such as initializing WebDriver and opening the required application.</p>

<h3>Q11. Why is @AfterMethod commonly used in Selenium?</h3>

<p>It is commonly used for cleanup such as capturing failure evidence and quitting the WebDriver session.</p>

<h3>Q12. What is alwaysRun?</h3>

<p><strong>alwaysRun</strong> is a TestNG configuration option that can be used when a configuration method should execute even when certain preceding conditions would otherwise prevent normal execution.</p>

<h3>Q13. What is the difference between @BeforeTest and @BeforeClass?</h3>

<p><strong>@BeforeTest</strong> is associated with a TestNG XML <strong>&lt;test&gt;</strong> section, while <strong>@BeforeClass</strong> is associated with the lifecycle of a test class.</p>

<h3>Q14. What is DataProvider?</h3>

<p><strong>@DataProvider</strong> supplies multiple sets of input data to a test method and is commonly used for data-driven testing.</p>

<h3>Q15. What is dependsOnMethods?</h3>

<p><strong>dependsOnMethods</strong> defines a dependency between test methods. A dependent test can be skipped if its required dependency does not complete successfully.</p>

<hr>

<h2>51. Quick Revision</h2>

<table border="1" cellpadding="8" cellspacing="0">

<tr><th>Annotation</th><th>Remember</th></tr>

<tr><td>@BeforeSuite</td><td>Before the suite</td></tr>

<tr><td>@AfterSuite</td><td>After the suite</td></tr>

<tr><td>@BeforeTest</td><td>Before a TestNG XML &lt;test&gt; section</td></tr>

<tr><td>@AfterTest</td><td>After a TestNG XML &lt;test&gt; section</td></tr>

<tr><td>@BeforeClass</td><td>Before the first test method in a class</td></tr>

<tr><td>@AfterClass</td><td>After test methods in a class</td></tr>

<tr><td>@BeforeMethod</td><td>Before every applicable test method</td></tr>

<tr><td>@AfterMethod</td><td>After every applicable test method</td></tr>

<tr><td>@BeforeGroups</td><td>Before specified test groups</td></tr>

<tr><td>@AfterGroups</td><td>After specified test groups</td></tr>

<tr><td>@Test</td><td>Defines a test method</td></tr>

<tr><td>@DataProvider</td><td>Supplies test data</td></tr>

</table>

<hr>

<h2>52. Learning Roadmap</h2>

<pre><code>Core Java

    |

    v

Selenium WebDriver

    |

    v

Locators

    |

    v

WebElements

    |

    v

Browser Interactions

    |

    v

Waits &amp; Synchronization

    |

    v

TestNG

    |

    +-- @Test

    +-- @BeforeSuite

    +-- @AfterSuite

    +-- @BeforeTest

    +-- @AfterTest

    +-- @BeforeClass

    +-- @AfterClass

    +-- @BeforeMethod

    +-- @AfterMethod

    +-- @BeforeGroups

    +-- @AfterGroups

    +-- @DataProvider

    |

    v

Assertions

    |

    v

Page Object Model

    |

    v

Automation Framework

    |

    v

Maven + Git

    |

    v

Reporting

    |

    v

Jenkins / CI/CD

    |

    v

Real-Time Selenium Project</code></pre>

<hr>

<h2>53. Summary</h2>

<p>TestNG annotations provide the structure required to control the lifecycle of automated tests. The <strong>@Test</strong> annotation defines test methods, while configuration annotations such as <strong>@BeforeSuite, @AfterSuite, @BeforeTest, @AfterTest, @BeforeClass, @AfterClass, @BeforeMethod, @AfterMethod, @BeforeGroups, and @AfterGroups</strong> control different setup and cleanup stages.</p>

<p>In Selenium automation, annotations are especially useful for WebDriver initialization, browser cleanup, test data preparation, screenshots, reporting, group-specific setup, and reusable framework architecture.</p>

<p>Understanding the scope and behavior of each annotation is essential for building organized, maintainable, and scalable Selenium + TestNG automation frameworks.</p>

<hr>

<h2>54. Course Resources</h2>

<p>Learn more about Selenium WebDriver, TestNG, automation frameworks, assertions, test execution, data-driven testing, and related automation concepts through the following resources:</p>

<p><a href="https://www.justacademy.co/course-detail/selenium-training" target="_blank" rel="noopener noreferrer">Selenium Training</a></p>

<p><a href="https://www.justacademy.co/register-for-course-demo" target="_blank" rel="noopener noreferrer">Register for Course Demo</a></p>

</div>

Previous Next
whatsapp