For 2–5 years of experience, TestNG interview questions focus on running large suites well: ThreadLocal drivers and parallel execution, listeners and retries, framework design for cross-browser runs, CI integration, and scenario questions such as tests that pass locally but fail in Jenkins.
Mid-Level (2–3 Years)
25. Explain ThreadLocal WebDriver. Why is it important?
ThreadLocal<WebDriver> stores a separate driver per thread. In parallel execution, multiple threads run simultaneously — if they share one driver instance, they interfere. ThreadLocal guarantees each thread gets its own browser. MUST call remove() in teardown to prevent memory leaks.
26. What is @Factory in TestNG?
Annotation on a method that returns Object[] of test class instances. Creates multiple instances of a test class, each with different constructor arguments. Each instance runs all @Test methods. Useful for running same tests with different users/configs.
27. Difference between @Factory and @DataProvider.
@DataProvider: one class instance, multiple test runs with different data. @Factory: creates multiple class instances — each instance can have completely different configuration, browser, user. Factory = multiple instances; DataProvider = multiple data inputs to one instance.
28. How do you apply RetryAnalyzer to ALL tests without adding it to each @Test?
Implement IAnnotationTransformer. In transform() method: annotation.setRetryAnalyzer(RetryAnalyzer.class). Register in testng.xml as a listener. This programmatically adds retry to every @Test annotation at runtime.
29. What is IAnnotationTransformer?
TestNG listener that intercepts annotation processing. transform() is called for each @Test before it runs. Can modify: retryAnalyzer, priority, groups, enabled, invocationCount, dataProvider. Used to add retry globally, modify groups dynamically.
30. How do you handle test data from Excel in TestNG?
Use Apache POI with @DataProvider. ExcelReader reads .xlsx file into Object[][]. @DataProvider returns the Object[][]. @Test receives the row data as parameters. Each row = one test execution. Useful for large datasets managed by business analysts.
31. Explain the complete flow of TestNG with ExtentReports.
1) TestListener implements ITestListener. 2) onTestStart: create ExtentTest. 3) onTestSuccess: mark pass. 4) onTestFailure: mark fail + add screenshot. 5) onFinish: extent.flush(). 6) Register listener in testng.xml. Thread-safe: use ThreadLocal<ExtentTest>.
32. What is @Test(dataProvider, dataProviderClass)?
dataProvider: name of the @DataProvider method. dataProviderClass: class where the @DataProvider method is defined — useful when data is in a separate TestDataFactory class, keeping test class clean.
33. How do you control the order of test classes in testng.xml?
Use preserve-order='true' in the <test> tag. Classes run in the order listed in testng.xml. Within a class, use @Test(priority) or preserve-order on methods. Without preserve-order, order is not guaranteed.
34. What is @Test(alwaysRun=true)?
The test runs even if it depends on a test that failed or was skipped. Use for teardown tests: @Test(dependsOnMethods={'testLogin'}, alwaysRun=true) public void testLogout() — logout should always run even if login failed.
35. How do you pass runtime parameters to tests in CI/CD?
In testng.xml use <parameter>. Override with Maven: -Dbrowser=firefox. In test: ConfigReader checks System.getProperty(key) before props file. In Jenkins pipeline: mvn test -Dbrowser=${params.BROWSER}. Allows environment-specific configs.
36. What is the difference between parallel='methods' and parallel='tests'?
parallel='methods': ALL @Test methods across ALL classes run in separate threads simultaneously. parallel='tests': each <test> XML tag runs in a separate thread — enables cross-browser (Chrome <test> and Firefox <test> run simultaneously).
Senior (3–4 Years)
37. Design a TestNG framework for cross-browser parallel testing.
testng.xml: parallel='tests', thread-count=3. Three <test> tags: Chrome, Firefox, Edge each with browser parameter. BaseTest: @BeforeMethod @Parameters('browser') calls DriverFactory.setDriver(browser). DriverFactory: ThreadLocal<WebDriver>. @AfterMethod: DriverFactory.quitDriver() with remove(). TestListener: ThreadLocal<ExtentTest>.
38. How do you handle flaky tests professionally?
1) Root cause first: is it timing (add explicit wait), data (isolate test data), environment (mock unstable deps)? 2) RetryAnalyzer with max 2 retries. 3) Apply globally via IAnnotationTransformer. 4) Track flaky count in reports. 5) Fix root cause — retry is a band-aid, not a solution.
39. What is ISuiteListener? When would you use it?
Interface with onStart(ISuite) and onFinish(ISuite). Fires at suite level — before all tests start and after all end. Use for: initialising global test data before suite, writing suite-level summary report, closing DB connections, sending final email with full report link.
40. How do you generate Allure reports with TestNG?
Add allure-testng dependency. @Description, @Step, @Attachment annotations in tests. allure.results in target/ after run. Command: allure serve target/allure-results. Reports show test steps, attachments, history trends. More powerful than ExtentReports for large teams.
41. What is @Test(invocationCount) combined with threadPoolSize?
invocationCount=10: run test 10 times. threadPoolSize=3: run those 10 invocations using 3 parallel threads. Use for load/stress testing a single function — simulates concurrent users hitting the same feature. Requires ThreadLocal driver.
42. How do you implement test logging at every step?
Implement IInvokedMethodListener. beforeInvocation: log method name and parameters. afterInvocation: log result. Alternatively, use @Step annotation from Allure for step-level logging. Log to ExtentTest.info() in listener.
43. How do you fail a test from a Listener?
In ITestListener.onTestFailure(), you cannot un-fail it. But in IInvokedMethodListener.afterInvocation(), you can call result.setStatus(ITestResult.FAILURE) and result.setThrowable(exception) to force fail. Use sparingly — better to let test itself handle assertions.
44. How do you skip a test programmatically?
Throw new SkipException('reason') from inside the test or from @BeforeMethod. TestNG catches it and marks the test as SKIPPED. Use for conditional skipping: if environment is down, skip all tests in that suite.
45. What is IAlterSuiteListener?
Listener that fires before the suite starts. Receives List<XmlSuite> and can modify the suite XML programmatically — add/remove tests, change parallel settings, inject parameters based on runtime conditions. Useful for dynamic test selection.
46. How do you prevent a test from running in a specific environment?
In @BeforeMethod, read environment from config: if (env.equals('production')) throw new SkipException('Skipping in prod'). Or use IAlterSuiteListener to remove tests from suite based on environment. Or use different testng.xml files per environment.
47. Explain data-provider-thread-count in testng.xml.
<suite data-provider-thread-count='4'> controls how many threads a parallel=true DataProvider uses. Default is 10. Setting this prevents too many concurrent browser instances when DataProvider is parallel.
48. What is the difference between preserve-order='true' and using priority?
preserve-order='true' in testng.xml: classes and methods run in the order written in XML / order in source. priority on @Test: explicit numeric order within a class. Both control ordering but operate at different levels.
Expert and Scenario-Based
49. Scenario: Tests pass locally but fail in Jenkins. How do you debug?
1) Check Console Output — read full error. 2) Headless mode in CI — add --headless=new to ChromeOptions. 3) Screen resolution — add --window-size=1920,1080. 4) Timing — CI slower, increase explicit waits. 5) Missing environment variables. 6) Path differences. 7) Run with -Dsurefire.useFile=false for full output.
50. Scenario: You need to run the same test suite across 5 environments (dev, staging, uat, preprod, prod). How?
5 testng.xml files (testng_dev.xml etc.) each with <parameter name='url' value='...'> and <parameter name='env' value='...'>. ConfigReader reads System.getProperty('env') first, then falls back to properties file. Jenkins: parameterised build with ENV dropdown. Run: mvn test -DsuiteXmlFile=testng_${env}.xml.
51. Scenario: Test generates unique test data (timestamp-based email). How do you pass it between dependent tests?
Use instance variables in the test class: private String email. In test1: email = 'user' + System.currentTimeMillis() + '@test.com'. In test2 (dependsOnMethods='test1'): use this.email. Works because same class instance runs all tests.
52. How do you run tests tagged as @Test(groups='smoke') from the command line?
mvn clean test -Dgroups=smoke. Maven Surefire passes this to TestNG. Alternatively, create testng_smoke.xml with <groups><run><include name='smoke'/></run></groups> and run: mvn test -DsuiteXmlFile=testng_smoke.xml.
53. How do you deal with TestNG report showing 'skipped' for retried tests?
Implement IReporter. In generateReport(), filter test results — exclude results with status SKIP that have throwable containing 'Retrying' (Mockito/TestNG adds retry message). Show only the final result per test. Or configure ExtentReports to not log intermediate retry results.
54. Design a TestNG setup for 100 test cases with 40% smoke, 80% regression, 20% sanity.
Group assignment: @Test(groups={'smoke','regression'}) for smoke tests. @Test(groups={'regression'}) for regression-only. @Test(groups={'sanity','regression'}) for sanity. Three testng.xml files with appropriate group includes. Pipeline: smoke on every PR, regression nightly, sanity on release.
55. How do you share test data between @BeforeMethod and @Test?
1) Instance variable: set in @BeforeMethod, read in @Test. 2) @BeforeMethod with attribute/return: use ITestResult.setAttribute() in @BeforeMethod, read with result.getAttribute() in @AfterMethod. 3) ThreadLocal for parallel safety. 4) Pass via constructor for @Factory tests.
56. What happens if @BeforeMethod fails?
The @Test method is SKIPPED (not failed) — TestNG assumes setup is broken. @AfterMethod with alwaysRun=true still runs. Without alwaysRun=true, @AfterMethod also skips. This is why alwaysRun=true on teardown is critical — browser must be closed.
57. How do you get the test method name and class name inside a test?
Inject ITestContext: @Test public void myTest(ITestContext ctx) {}. Or inject ITestResult in @AfterMethod. result.getName() = method name. result.getTestClass().getName() = class name. result.getMethod().getDescription() = description text.
58. How do you create a custom TestNG reporter that exports to CSV?
Implement IReporter. Override generateReport(List<XmlSuite> suites, List<ISuite> iSuites, String outputDir). Loop through iSuites → ISuiteResult → ITestContext → getPassedTests/getFailedTests/getSkippedTests. Write each result row to CSV using FileWriter.
59. What is the difference between @BeforeGroups and @BeforeClass for group setup?
@BeforeGroups('smoke'): runs once before the FIRST test in the 'smoke' group executes — regardless of which class it's in. @BeforeClass: runs before each class. Use @BeforeGroups for group-specific data setup that spans multiple classes.
60. How do you ensure your TestNG framework scales from 100 to 1000 test cases?
1) Parallel execution: parallel='methods', thread-count=10. 2) ThreadLocal driver: no shared state. 3) Test tagging: smoke/regression/sanity — run appropriate sets. 4) Data-driven: @DataProvider replaces duplicate tests. 5) Page Object Model: maintainable when UI changes. 6) CI gate: fail on >5% failure rate. 7) JaCoCo or coverage tool. 8) Allure for detailed reporting at scale.
FAQs
What TestNG topics do senior interviews cover?
Parallel execution with ThreadLocal, listeners and retry analyzers, factories, suite design for cross-browser and environment runs, CI integration and how you debug flaky failures.