Use TestNG as the Java test runner and organizer, and Selenium WebDriver as the browser-control layer. A TestNG @Test method can create a driver, navigate to a page, interact with elements, and assert results. TestNG annotations control setup and cleanup, while testng.xml, groups, parameters, and your build tool determine what runs.
This guide builds a maintainable project from dependencies through local execution, suite selection, parallel design, troubleshooting, and an API option for teams that need rendered screenshots.
What TestNG and Selenium each do
Selenium WebDriver opens a browser session and sends commands such as navigation, element lookup, clicks, typing, and script execution. It does not own assertions, pass/fail decisions, test selection, or reporting. The Selenium project describes those responsibilities as belonging to a test framework; TestNG and JUnit are common Java choices. See Selenium components and Selenium’s runner guidance.
TestNG supplies the test lifecycle and execution model:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11#1 Best Overall
@Testmarks a test method.@BeforeMethodand@AfterMethodrun around each test method.@BeforeClass,@AfterClass,@BeforeSuite,@AfterSuite, and related annotations support broader scopes.- Groups, data providers, parameters, and parallel policies help select and organize runs.
- A suite XML file can name suites, tests, classes, and methods for repeatable execution.
The practical pattern is therefore: configure both libraries, create a driver in a deliberate lifecycle hook, perform browser work in @Test, assert an outcome, and always quit the session.
Prerequisites and version checks
- A JDK supported by the versions you select. The TestNG homepage currently displays 7.9.0 as its current release and states that TestNG 7.6.0 and later require JDK 11 or higher. Confirm the current release and compatibility at testng.org before copying a version into a new project.
- Maven or Gradle, or another build system that can run Java tests.
- A browser such as Chrome, Firefox, or Edge. Selenium’s driver setup and local-versus-remote guidance are documented at Driver Sessions.
- An IDE with a JDK configured for the project.
Selenium’s installation page uses a version placeholder rather than claiming one universal latest version. Select a Selenium Java version compatible with your JDK, browser, and build environment by following the official installation instructions.
Create the project dependencies
Maven
Add Selenium and TestNG as test dependencies. Replace the placeholders with versions verified from the projects’ current release information.
<properties>
<maven.compiler.release>11</maven.compiler.release>
<selenium.version>YOUR_SELENIUM_VERSION</selenium.version>
<testng.version>YOUR_TESTNG_VERSION</testng.version>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Configure your Maven test plugin according to the TestNG documentation if your project needs a suite XML file or specific provider behavior. The reference is TestNG Documentation.
Gradle
dependencies {
testImplementation "org.seleniumhq.selenium:selenium-java:YOUR_SELENIUM_VERSION"
testImplementation "org.testng:testng:YOUR_TESTNG_VERSION"
}
test {
useTestNG()
}
Keep versions in one place and update them deliberately. A dependency that resolves successfully can still be unsuitable for your JDK, browser, or CI image.
Write a first TestNG Selenium test
The following class creates one browser session per test method. That scope gives each test a clean starting state and makes failures less dependent on execution order.
package example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class HomePageTest {
private WebDriver driver;
@BeforeMethod
public void startBrowser() {
driver = new ChromeDriver();
}
@Test
public void pageHasExpectedTitle() {
driver.get("https://www.selenium.dev/");
String title = driver.getTitle();
Assert.assertTrue(title.toLowerCase().contains("selenium"),
"Unexpected title: " + title);
}
@Test
public void documentationLinkIsPresent() {
driver.get("https://www.selenium.dev/");
Assert.assertTrue(driver.findElement(By.linkText("Documentation")).isDisplayed());
}
@AfterMethod(alwaysRun = true)
public void stopBrowser() {
if (driver != null) {
driver.quit();
}
}
}
This follows Selenium’s Java first-script sequence—construct a ChromeDriver, navigate, interact, and call quit()—while TestNG supplies the annotations and assertion flow. See Write your first Selenium script.
Rank #2
Why cleanup uses alwaysRun
If setup or the test fails, cleanup should still be attempted. Checking for null avoids a second exception when the driver was never created. quit() closes the session and its windows; do not rely on closing one tab to release the whole browser process.
Choose the right TestNG lifecycle scope
| Scope | Use it for | Browser-session implication |
|---|---|---|
@BeforeMethod/@AfterMethod |
Independent tests | New session for every method; strongest isolation. |
@BeforeClass/@AfterClass |
A class whose methods intentionally share setup | One session for the class; state can leak between methods. |
@BeforeTest/@AfterTest |
Configuration around a TestNG XML <test> |
Scope follows the XML test, not an individual method. |
@BeforeSuite/@AfterSuite |
Suite-wide, non-browser resources | Sharing a browser this broadly increases coupling and cleanup risk. |
@BeforeGroups/@AfterGroups |
Preparation for named groups | Useful for group-specific data or services. |
TestNG documents all of these hooks. A browser is usually safest at method or class scope; choose a wider scope only when the state sharing is intentional and synchronized.
Run tests from Maven, Gradle, or an IDE
Maven
mvn test
To select a class or method, use your Maven TestNG provider’s documented configuration, or select the test from your IDE. Keep CI selection in version-controlled configuration rather than relying on a developer’s local run configuration.
Gradle
./gradlew test
The useTestNG() setting tells Gradle to discover TestNG tests. You can further configure included groups, excluded groups, listeners, and suite files in the Gradle test task.
IDE
Import the project as Maven or Gradle, confirm the test class is under the test source set, then run the class or method with the IDE’s TestNG integration. If the IDE reports that no tests were found, check the dependency scope, annotation import (org.testng.annotations.Test), and source-directory layout.
Use testng.xml for repeatable selection
A TestNG XML file represents a suite and can contain one or more named tests. Each XML test can include classes and, when needed, selected methods.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="smoke-suite">
<test name="home-page">
<classes>
<class name="example.HomePageTest"/>
</classes>
</test>
</suite>
Use the file when a named smoke run, a stable CI selection, parameters, groups, or a multi-class suite is easier to understand in XML than in command-line flags. Keep it small and descriptive; a large, hand-maintained list can become another source of drift.
Rank #3
Groups and parameters
Annotate a method with groups when the same code belongs to multiple run selections:
@Test(groups = {"smoke", "checkout"})
public void checkoutLoads() {
// browser steps
}
For environment-specific values, TestNG can pass XML parameters into a method:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors@Parameters("baseUrl")
@Test
public void opensConfiguredSite(String baseUrl) {
driver.get(baseUrl);
}
Declare the parameter on the XML <test> element, then keep secrets out of source control. Data providers are preferable when one test method must run against a set of structured input rows.
Parallel execution without unsafe shared state
TestNG supports parallel policies and Selenium documents local and remote execution, including Selenium Server/Grid, in its architecture and driver guidance. Parallel execution is not automatically faster or more reliable: tests that share a static driver, account, file, or database record can interfere with one another.
- Create a separate driver per parallel test thread or method.
- Use isolated users and unique test data.
- Avoid mutable static fields for session state.
- Set an explicit parallel mode and thread count in your build or suite configuration.
- Start with a small subset and inspect failures for race conditions before expanding concurrency.
Remote execution adds network and infrastructure failure modes. Treat session startup, browser capabilities, timeouts, and artifact collection as configurable environment concerns rather than assumptions in the test method.
Assertions, waits, and maintainability
Assert outcomes, not implementation details
Place assertions at the point where the expected user-visible result is known. A title, URL, visible message, enabled control, or resulting state is generally more useful than asserting that an internal click command returned.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Wait for conditions instead of sleeping
Dynamic pages may render after navigation. Prefer Selenium’s explicit waits for a specific condition over arbitrary thread sleeps. This reduces unnecessary delay while making the intended synchronization visible.
Rank #4
Keep locators and test data deliberate
- Prefer stable IDs, accessible labels, or purpose-built data attributes.
- Keep page interactions in page objects or small helper methods when multiple tests use them.
- Do not hide every failure behind broad exception handling; preserve the original cause.
- Capture screenshots, HTML, and logs on failure through your test listener or build artifacts.
Common failures and fixes
“NoSuchDriver” or browser startup failure
Check that the browser is installed, the selected Selenium version supports your JDK, and the CI image permits the driver to start. Read the driver-session and installation guidance before hard-coding a driver path.
“Cannot find symbol” for TestNG annotations
Verify the TestNG dependency is on the test classpath and that imports use org.testng.annotations.*. Reimport the Maven or Gradle project after editing the build file.
No tests are discovered
Confirm the method is public where your setup requires it, has @Test, resides in the test source set, and is included by the build’s TestNG configuration. An XML suite that names the wrong fully qualified class also produces an empty run.
Free tools Windows power users keep installed
One-click scans. No signup required.
The browser remains open after a failure
Use @AfterMethod(alwaysRun = true), guard against a null driver, and call quit() rather than only closing the current window.
Flaky element or timeout errors
Inspect whether the page is still loading, an iframe or window must be selected, a locator is unstable, or a cookie/consent overlay blocks the target. Replace fixed sleeps with a condition that represents readiness and collect a failure screenshot and page source.
Parallel tests contaminate one another
Look for static drivers, reused accounts, shared download paths, and non-unique records. Make those resources thread-local or unique, or reduce parallelism until the test design is isolated.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your purpose is to obtain a rendered page image rather than drive assertions and interactions, ScreenshotNeo provides a website screenshot API and MCP server. It accepts a URL in one request and can return PNG, JPEG, WebP, or PDF. Before capture it can accept cookie/consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing result.
Best Value
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the complete option names and response behavior in the ScreenshotNeo documentation. Options include full-page lazy-image capture, CSS-selector element capture, dark mode, device presets, custom viewport and retina scale, PDF paper settings and page ranges, custom CSS or JavaScript, clicks, waits, ad/tracker/request blocking, headers, cookies, user agent, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTL, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.
An MCP server supplies take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Is TestNG part of Selenium?
No. Selenium WebDriver drives browsers, while TestNG is a separate Java test framework that runs and organizes tests.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Should I create one driver for the whole suite?
Usually not for independent tests. A per-method or per-class session limits state leakage; suite-wide reuse is a deliberate optimization with higher coupling.
Do I need testng.xml for every project?
No. Annotation-based discovery through Maven, Gradle, or an IDE is enough for small projects. Add XML when named selection, parameters, groups, or repeatable CI suites justify it.
Can TestNG run Selenium tests remotely?
Yes. TestNG executes the Java methods while Selenium can create sessions against a remote Selenium Server or Grid. Configure remote capabilities and isolate data just as you would for parallel local runs.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.

