Automation Interview
TestNG Interview Questions and Answers
TestNG interview questions and answers on annotations, testng.xml, data providers, groups, parallel execution, assertions, listeners, and retry logic.
2,216 words | Article schema | FAQ schema | Breadcrumb schema
Overview
TestNG is the backbone of most Java automation frameworks, and interviewers treat it as a proxy for whether you can control a real suite. Anyone can add a @Test annotation. The questions that matter probe how you sequence, group, parameterize, parallelize, and stabilize hundreds of tests without the suite turning into chaos. This guide walks through those questions with the answers that show you have run TestNG at scale, not just followed a tutorial.
Think of TestNG as a control room. Annotations set up and tear down state at the right scope, testng.xml decides what runs and how, groups and dependencies shape execution, and listeners and retry analyzers handle reporting and flake. An interviewer who asks about @BeforeClass versus @BeforeMethod is really asking whether you understand execution scope, which is the difference between a fast, isolated suite and a slow, tangled one.
Each answer below pairs the concept with the practical decision it drives, with short inline snippets where they clarify. If you can explain not just what an annotation does but why you would choose it, you will handle the follow-ups that separate strong candidates from memorizers.
Why TestNG Questions Are Really About Control
TestNG earns its place over plain JUnit in large suites because of control: flexible configuration through XML, powerful grouping, built-in data providers, dependency management, and native parallel execution. When an interviewer opens with tell me why your team uses TestNG, they want those reasons, not a definition. The strongest answers connect each feature to a problem it solved on a real project.
- Annotations control setup and teardown at suite, test, class, and method scope.
- testng.xml controls which tests, groups, and parameters run, and how they parallelize.
- Groups and dependencies control ordering and selective execution.
- Listeners and retry analyzers control reporting and flaky-test handling.
The Annotation Hierarchy
`Explain the order of @BeforeSuite, @BeforeTest, @BeforeClass, and @BeforeMethod.` They fire from broadest to narrowest scope. @BeforeSuite runs once for the whole suite (start a Grid or read global config), @BeforeTest once per test tag in the XML, @BeforeClass once before the first method of a class (create the driver for that class), and @BeforeMethod before every single test method (reset state or navigate to a start page). The After variants mirror them in reverse. Choosing the right scope is the whole game: put driver creation in @BeforeMethod and you pay for a new browser every test, while putting per-test state there keeps tests isolated.
- @BeforeSuite and @AfterSuite: once per suite (global setup like a Grid or config load).
- @BeforeTest and @AfterTest: once per test tag in testng.xml.
- @BeforeClass and @AfterClass: once per class (a common spot for driver lifecycle).
- @BeforeMethod and @AfterMethod: before and after each test (state reset, isolation).
Controlling Order: priority and dependsOnMethods
`How do you control the order tests run in?` By default TestNG does not guarantee method order, so relying on alphabetical execution is a trap. Use priority to set an explicit sequence (lower runs first), and use dependsOnMethods when a test genuinely requires another to succeed first, which also skips the dependent test if the prerequisite fails rather than failing it noisily. The nuance interviewers want: dependencies model real prerequisites like login before checkout, while priority is just ordering. Overusing dependencies couples tests and hurts isolation, so lean on independent tests wherever you can.
- Method order is not guaranteed by default; never assume alphabetical.
- priority sets explicit order, and lower numbers run first.
- dependsOnMethods enforces prerequisites and skips dependents when they break.
- Prefer independent tests; heavy dependency chains reduce isolation and parallelism.
Grouping and Selective Runs
`How do you run only smoke tests from a large suite?` Tag tests with groups, for example a smoke group, then include or exclude groups in testng.xml or from the command line. This lets one codebase serve a fast smoke gate on every commit and a full regression nightly, without duplicating tests. You can also define group dependencies with dependsOnGroups so an entire category runs only after another passes. Grouping is how you turn a monolithic suite into tiered pipelines.
- Tag tests with groups such as smoke, regression, or sanity.
- Include or exclude groups in testng.xml or from the command line.
- dependsOnGroups sequences whole categories of tests.
- Groups enable tiered pipelines: fast smoke per commit, full run nightly.
Parameterizing Tests: Parameters vs DataProvider
`What is the difference between @Parameters and @DataProvider?` @Parameters injects a small number of values defined in testng.xml, ideal for environment-level inputs like a browser name or base URL. @DataProvider supplies data-driven inputs from code, returning a two-dimensional array or an iterator, so the same test runs once per row: perfect for many input combinations from a CSV, Excel, JSON, or database source. Rule of thumb: @Parameters for a handful of config values from XML, @DataProvider for real data-driven testing in code.
A sharp follow-up is `how do you make a DataProvider run in parallel?` Set parallel equal to true on the @DataProvider annotation, which runs its rows concurrently, and make sure the test and any shared state are thread-safe first. This is a favorite because it exposes whether you have actually parallelized data-driven runs or only read about it.
- @Parameters: a few values from testng.xml (browser, environment, URL).
- @DataProvider: many rows from code (CSV, Excel, JSON, DB) for data-driven runs.
- A DataProvider returns a two-dimensional Object array or an iterator.
- Setting parallel to true on a DataProvider runs rows concurrently if state is thread-safe.
Factory vs DataProvider (the question people miss)
`What is the difference between @Factory and @DataProvider?` This one filters the people who have read deeply. A @DataProvider feeds different data to the same test method, running that method multiple times. A @Factory creates multiple instances of a test class, so every test in the class runs against each instance, often with different constructor arguments. Use a DataProvider to vary inputs to one test, and use a Factory to run a whole class of tests across several configurations or objects. Confusing the two is common and easy for an interviewer to probe.
- @DataProvider: same method, many data rows.
- @Factory: many instances of a test class, each running all its methods.
- DataProvider varies inputs; Factory varies the objects under test.
- Combine them: a Factory can build instances that a DataProvider then feeds.
Assertions: Hard vs Soft
`What is the difference between a hard assertion and a soft assertion?` A hard assertion (the static Assert methods) stops the test immediately on the first failure, so nothing after it runs. A SoftAssert collects failures and reports them only when you call assertAll() at the end, letting the test check several things in one run before failing. Use soft assertions when you want to validate many independent fields on a page in one pass, and use hard assertions when a failure makes the rest of the test meaningless. Forgetting to call assertAll() is a classic bug: the test passes even though soft assertions failed, because the failures are never reported.
- Hard assertion: stops at the first failure (Assert.assertEquals and friends).
- Soft assertion: collects failures, reported only at assertAll().
- Soft fits multiple independent field checks in one test pass.
- Forgetting assertAll() silently hides failures, which is a frequent real bug.
Parallel Execution and Thread Safety
`How do you run TestNG tests in parallel, and what breaks?` Set the parallel attribute in testng.xml (values like methods, classes, tests, or instances) and a thread-count. The catch is thread safety: a shared WebDriver or shared mutable state will collide across threads. The standard fix is a ThreadLocal WebDriver so each thread gets its own driver instance, created in setup and removed in teardown. Interviewers ask this because parallel execution is where naive frameworks fall apart, and a ThreadLocal driver is the answer they are listening for.
- Set parallel (methods, classes, tests, instances) and a thread-count in testng.xml.
- Shared static state and a shared driver are the usual failures.
- Give each thread its own driver with a ThreadLocal WebDriver.
- Keep test data isolated so parallel tests never fight over the same records.
Retrying Flaky Tests: IRetryAnalyzer
`How do you automatically retry a failed test in TestNG?` Implement IRetryAnalyzer, returning true from retry() up to a set maximum, and attach it to tests (per test or globally with a listener). This reruns a failing test a bounded number of times, which can absorb genuine intermittent infrastructure blips. The honest caveat interviewers want to hear: retries are a safety net, not a cure. Blindly retrying masks real bugs, so pair it with tracking so that a test which only passes on retry gets investigated and fixed, not left to hide a defect.
- Implement IRetryAnalyzer and cap the retry count.
- Attach it per test or globally through an IAnnotationTransformer listener.
- Retries absorb infrastructure blips, not logic bugs.
- Track retry-passes so flake gets fixed, not permanently masked.
Listeners and Reporting Hooks
`What are TestNG listeners and how have you used them?` Listeners are interfaces that hook into the test lifecycle so you can run code on events. ITestListener fires on test start, success, failure, and skip, and the classic use is capturing a screenshot and logging on onTestFailure, then attaching it to an Extent or Allure report. Other listeners let you transform annotations at runtime or observe the whole suite. Listeners are how you centralize reporting and diagnostics instead of copying try or catch logic into every test.
- ITestListener reacts to start, success, failure, and skip events.
- onTestFailure is the natural place for screenshots and failure logs.
- IAnnotationTransformer can attach a retry analyzer to every test.
- Register listeners in testng.xml or with the @Listeners annotation.
testng.xml, the Control Room
`What goes in testng.xml and why not just run classes directly?` The XML is where you compose the run without touching code: which classes and packages, which groups to include or exclude, parameters to inject, parallel mode and thread count, and listeners. It lets one framework produce many run profiles (smoke, regression, cross-browser) that CI can call by name. Being able to describe a real testng.xml, with a test tag per browser passing a parameter, signals that you have configured suites for a pipeline rather than clicking run in an IDE.
- Selects classes, packages, and methods to run without code changes.
- Includes or excludes groups and injects @Parameters values.
- Sets parallel mode, thread-count, and registers listeners.
- Enables multiple profiles (smoke, regression, cross-browser) for CI.
TestNG vs JUnit and Common Wrong Answers
`Why choose TestNG over JUnit?` For large Selenium suites, TestNG offers richer built-in features: flexible XML-based configuration, powerful grouping, native data providers, dependency management, and simpler parallel execution, all without extra runners. JUnit 5 has closed much of the gap, so the honest answer acknowledges both and ties the choice to suite size and team needs rather than claiming one is universally superior. The wrong answers below are easy to trip on if you only skimmed the docs.
- Claiming TestNG guarantees method order by default. It does not; use priority or dependencies.
- Saying soft assertions fail the test on the spot. They only report at assertAll().
- Confusing @Factory with @DataProvider. One makes instances, the other feeds data.
- Describing parallel execution without mentioning ThreadLocal or thread safety.
- Treating a retry analyzer as a fix for flaky tests instead of a monitored safety net.
Frequently Asked Questions
What is the execution order of TestNG annotations?
From broadest to narrowest scope: @BeforeSuite, @BeforeTest, @BeforeClass, @BeforeMethod, the test, then the matching After annotations in reverse. Choosing the right scope for setup such as driver creation is what keeps a suite fast and isolated.
What is the difference between @Parameters and @DataProvider in TestNG?
@Parameters injects a few values defined in testng.xml, good for environment inputs like browser or URL. @DataProvider supplies many data rows from code (CSV, Excel, JSON, or a database) so the same test runs once per row for data-driven testing.
How do you run TestNG tests in parallel?
Set the parallel attribute (methods, classes, tests, or instances) and a thread-count in testng.xml, then make the framework thread-safe with a ThreadLocal WebDriver and isolated test data so parallel threads do not collide.
What is the difference between hard and soft assertions?
A hard assertion stops the test at the first failure. A SoftAssert collects failures and reports them only when you call assertAll(), which lets one test verify several fields in a single run. Forgetting assertAll() hides failures.
How do you handle flaky tests in TestNG?
Implement IRetryAnalyzer to rerun a failing test a bounded number of times, attached per test or globally via a listener. Treat it as a monitored safety net: track retry-passes and fix the root cause rather than letting retries mask real bugs.
Is TestNG better than JUnit?
For large Selenium suites, TestNG offers richer built-in grouping, XML configuration, data providers, and parallel execution. JUnit 5 has narrowed the gap, so a strong answer ties the choice to suite size and team needs rather than claiming one is universally better.