You've spent five chapters building TestNG skills in isolation: lifecycle annotations, data providers, parallel execution, listeners, retry logic, and CI integration. This chapter puts everything together in one production-ready framework. The goal is not another tutorial — it is a portfolio-grade GitHub repository that demonstrates every skill from this course in a coherent, working project. By the end you will have a Selenium + TestNG framework a senior QA engineer would recognise as professional: properly structured, parallelised, data-driven, equipped with rich reporting, and running automatically in CI on every push.
The project
You are building a test framework for a task management application. Use any publicly available task manager (Trello, Asana's demo environment, a to-do app like TodoMVC, or a self-hosted demo app). The specific application matters less than the testing surface it provides: login, create/read/update/delete flows, form validation, multi-step processes, and some UI state that can fail.
If you want a backend-driven application with an API alongside the UI, JSONPlaceholder or ReqRes make good API targets for the data-provider exercises.
The ten deliverables
Every deliverable maps directly to a chapter you have worked through:
1. Maven project skeleton (Chapter 1)
pom.xml with selenium-java, testng, webdrivermanager, poi-ooxml, jackson-databind, extentreports (or allure-testng), and maven-surefire-plugin 3.2.5. Standard src/test/java / src/test/resources layout. Add target/, test-output/, reports/, and screenshots/ to .gitignore.
2. DriverManager with ThreadLocal (Chapter 4)
DriverManager.java with ThreadLocal<WebDriver>, initDriver(browser, options), getDriver(), and quitDriver(). Headless mode controlled by a System.getProperty("headless", "false") flag. BaseTest.java extends nothing but wires @BeforeMethod @Parameters("browser") to DriverManager.initDriver() and @AfterMethod(alwaysRun = true) to DriverManager.quitDriver().
3. Page Objects (Chapter 1 — Selenium course, applied here)
At minimum: LoginPage, DashboardPage, TaskCreatePage, TaskDetailPage. Each extends a BasePage that holds the getDriver() reference and provides click(By), type(By, String), getText(By), isDisplayed(By), and waitForElement(By) helpers.
4. TestNG suite files (Chapters 1 + 2)
Three XML files in src/test/resources/: smoke.xml (groups=smoke, thread-count=1), regression.xml (groups=regression, thread-count=2, parallel=classes, excludes wip), cross-browser.xml (parallel=tests, thread-count=2, Chrome + Firefox blocks via <parameter name="browser">).
5. At least 20 test methods (Chapters 1–3) Distributed across:
- Smoke (5): login happy path, home page loads, create task, task appears in list, logout
- Regression — validation (5): empty form submit, invalid email format, duplicate task name, XSS in task title field, very long text input
- Regression — flows (5): edit task, mark task complete, delete task, filter by status, sort by date
- Data-driven (5): login scenarios from JSON, task creation from Excel — at least two DataProvider methods with 5+ rows each
6. DataProvider tests from external files (Chapter 3)
One @DataProvider reading from testdata/login-scenarios.json (4+ rows covering valid, invalid, locked, empty email) and one from testdata/task-data.xlsx (5+ rows with task title, priority, due date, expected result). Use DataReader utility from Chapter 3 to keep file I/O out of test classes.
7. RetryAnalyzer + RetryTransformer (Chapter 4)
RetryAnalyzer with MAX_RETRIES = 2. RetryTransformer wires it to every @Test globally via testng.xml. RetryResultCleaner listener removes initial-failure results for tests that eventually pass. At least one test method has Thread.sleep(200) to simulate a timing-sensitive operation worth retrying.
8. Listeners: screenshot + report (Chapters 4 + 5)
TestListener implementing ITestListener: screenshot on failure (to reports/screenshots/), console output with duration, ITestResult status check. Wired to ExtentReports or Allure for rich HTML output. All listeners registered in testng.xml — no @Listeners annotations in test classes.
9. CI pipeline (Chapter 5)
.github/workflows/testng.yml with two jobs: smoke on every push/PR, regression on nightly schedule. Java 21 (Temurin) with Maven cache. Secrets for BASE_URL and ADMIN_PASS. if: always() on artifact upload. --headless=new --no-sandbox --disable-dev-shm-usage Chrome flags in CI.
10. README
Documents: prerequisites (Java 21, Maven 3.9), how to run each suite (mvn test -DsuiteXmlFile=smoke.xml), how to pass environment variables (-DbaseUrl=... -Dbrowser=firefox), where reports are generated, how to view Allure results (allure serve allure-results).
Stretch goals
Once the core ten are working:
@Factoryfor multi-environment runs (Chapter 3). Create a factory that produces instances for staging, UAT, and production environments, each with a differentbaseUrl. Add anenvironments.jsonfile that the factory reads. Runfactory-suite.xml— same 20 tests run against three environments.IMethodInterceptorfor priority ordering (Chapter 4). Add@Severityannotations to tests. ImplementSeverityInterceptorso CRITICAL tests always run first. A fast CRITICAL failure means you find out before the full suite finishes.- Custom
@Ownerannotation and reporter. Annotate every test with@Owner("name"). UpdateSummaryReporterto group failures by owner and include the list in the email body — teams know immediately who to contact when a test fails. - Allure trend history. Add
allure-mavenplugin. Set up the GitHub Actions workflow to generateallure-historyfrom previous run artifacts. After 5 CI runs, the Allure dashboard shows a trend line.
Pick one stretch goal. Don't attempt all four — one done well is worth more than four started.
Deliverables mapped to this course
- – Maven pom.xml + Surefire 3.2.5
- – Annotations + lifecycle order
- – testng.xml: smoke + regression + cross-browser
- – Parameters for browser + baseUrl
- – @DataProvider from JSON + Excel
- – DataReader utility (classpath-safe)
- – @Factory for multi-environment instances
- – Parallel DataProvider iterations
- – ThreadLocal<WebDriver> DriverManager
- – RetryAnalyzer + RetryTransformer
- – ITestListener + screenshot-on-failure
- – IAnnotationTransformer + @WIP
- ExtentReports or Allure listener –
- GitHub Actions: smoke + nightly –
- Headless Chrome flags for CI –
- Secrets via GitHub Actions variables –
Acceptance criteria
The project is complete when, starting from a fresh clone:
git clone https://github.com/<you>/testng-framework
cd testng-framework
mvn clean test -DsuiteXmlFile=smoke.xml -Dheadless=true…the smoke suite runs green without any manual setup beyond Java 21 and Maven. The README makes clear how to run regression and cross-browser suites. The GitHub Actions workflow shows green on the repository's Actions tab. The reports/extent-report.html (or Allure results) is uploaded as a CI artefact and contains pass/fail data with at least one embedded screenshot from a failure you forced.
That is the bar professional frameworks are held to, and it is what you show in a technical interview when "TestNG" is on your CV.
Project work
Set up the skeleton and commit it. 45–60 minutes.
- Create a new GitHub repo:
testng-selenium-framework. Public is fine — this is a portfolio piece. - Scaffold the Maven project locally with the package structure:
testng-selenium-framework/ ├── pom.xml ├── README.md ├── .gitignore ├── .github/workflows/testng.yml └── src/test/ ├── java/com/mycompany/tests/ │ ├── annotation/ ← @WIP, @Owner, @Severity │ ├── base/ ← BaseTest, BasePage, DriverManager │ ├── data/ ← DataReader, LoginScenario POJO │ ├── listener/ ← TestListener, ExtentReportListener, RetryTransformer │ ├── pages/ ← LoginPage, DashboardPage, TaskCreatePage │ ├── retry/ ← RetryAnalyzer, RetryResultCleaner │ └── tests/ ← LoginTest, TaskTest, DataDrivenTest └── resources/ ├── smoke.xml ├── regression.xml ├── cross-browser.xml └── testdata/ ├── login-scenarios.json └── task-data.xlsx - Add all dependencies to
pom.xml. Runmvn dependency:treeand confirm all artifacts resolve. Runmvn clean testwith no test classes yet — expectTests run: 0, BUILD SUCCESS. - Push to GitHub. Confirm the Actions workflow file is present and the workflow tab shows a run (even if it fails because tests don't exist yet — that's expected).
- Pick your target application and note the base URL, login credentials for a test account, and the key locators for the login form. This is the only research you need before the walkthrough in the next lesson.
The next lesson provides complete code for every key class in the framework.