Java Selenium Project Structure
Here is the enhanced Java, TestNG, Selenium, Maven project structure that incorporates Page Object Model (POM) with PageFactory, along with a .github
folder for CI/CD pipelines (e.g., nightly and per-push builds) and a .gitignore
file.
Project Structure
MyAutomationProject/
├── .github/
│ └── workflows/
│ ├── nightly-build.yml # Nightly build pipeline
│ ├── push-build.yml # Build triggered on push
├── .gitignore # Files and folders to ignore in git
├── pom.xml # Maven configuration file
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── myproject/
│ │ │ ├── base/
│ │ │ │ ├── BaseTest.java # Base class for tests
│ │ │ │ └── DriverFactory.java # Manages WebDriver instances
│ │ │ ├── config/
│ │ │ │ └── ConfigReader.java # Reads configuration files
│ │ │ ├── pages/
│ │ │ │ ├── LoginPage.java # Login Page with PageFactory
│ │ │ │ └── DashboardPage.java # Dashboard Page with PageFactory
│ │ │ └── utils/
│ │ │ ├── TestUtils.java # Shared utility methods
│ │ │ └── WaitUtils.java # Explicit wait utility
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── myproject/
│ │ ├── tests/
│ │ │ ├── LoginTest.java # Test cases for Login
│ │ │ └── RegressionSuite.java # Regression Test Suite
│ │ ├── listeners/
│ │ │ └── TestListener.java # TestNG listener implementation
│ │ └── data/
│ │ └── TestDataProvider.java # Data provider for tests
│ └── resources/
│ ├── testng.xml # TestNG suite configuration
│ └── config.properties # Configuration properties
└── target/ # Maven build output
Example Files
.gitignore
# Maven specific files
target/
*.iml
# IntelliJ IDEA project files
.idea/
*.ipr
*.iws
*.iml
# Eclipse project files
.classpath
.project
.settings/
# OS-specific files
.DS_Store
# Log files
*.log
# Build-related files
*.class
.github/workflows/nightly-build.yml
name: Nightly Build
on:
schedule:
- cron: '0 2 * * *' # Runs every day at 2 AM UTC
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'adopt'
- name: Install dependencies
run: mvn install
- name: Run tests
run: mvn test
.github/workflows/push-build.yml
name: Build on Push
on:
push:
branches:
- main
- 'feature/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'adopt'
- name: Install dependencies
run: mvn install
- name: Run tests
run: mvn test
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myproject</groupId>
<artifactId>MyAutomationProject</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.14.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.8.0</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.4.0</version>
</dependency>
</dependencies>
</project>
BaseTest.java
package com.myproject.base;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
public class BaseTest {
protected WebDriver driver;
@BeforeMethod
public void setup() {
driver = DriverFactory.getDriver();
driver.manage().window().maximize();
}
@AfterMethod
public void teardown() {
if (driver != null) {
driver.quit();
}
}
}
DriverFactory.java
package com.myproject.base;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class DriverFactory {
public static WebDriver getDriver() {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
}
}
ConfigReader.java
package com.myproject.config;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class ConfigReader {
private static Properties properties;
static {
try (FileInputStream fis = new FileInputStream("src/test/resources/config.properties")) {
properties = new Properties();
properties.load(fis);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load config.properties");
}
}
public static String get(String key) {
return properties.getProperty(key);
}
}
LoginPage.java
package com.myproject.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPage {
private WebDriver driver;
@FindBy(id = "username")
private WebElement usernameField;
@FindBy(id = "password")
private WebElement passwordField;
@FindBy(id = "login")
private WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void login(String username, String password) {
usernameField.sendKeys(username);
passwordField.sendKeys(password);
loginButton.click();
}
}
WaitUtils.java
package com.myproject.utils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public class WaitUtils {
public static void waitForElement(WebDriver driver, WebElement element, int timeout) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));
wait.until(ExpectedConditions.visibilityOf(element));
}
}
LoginTest.java
package com.myproject.tests;
import com.myproject.base.BaseTest;
import com.myproject.pages.LoginPage;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginTest extends BaseTest {
@Test
public void testLogin() {
driver.get("https://example.com/login");
LoginPage loginPage = new LoginPage(driver);
loginPage.login("testuser", "password");
Assert.assertEquals(driver.getTitle(), "Dashboard");
}
}
TestListener.java
package com.myproject.listeners;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class TestListener implements ITestListener {
@Override
public void onTestSuccess(ITestResult result) {
System.out.println("Test Passed: " + result.getName());
}
@Override
public void onTestFailure(ITestResult result) {
System.out.println("Test Failed: " + result.getName());
}
}
TestDataProvider.java
package com.myproject.data;
import org.testng.annotations.DataProvider;
public class TestDataProvider {
@DataProvider(name = "loginData")
public Object[][] loginData() {
return new Object[][] {
{"user1", "password1"},
{"user2", "password2"}
};
}
}
testng.xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="MyAutomationSuite">
<listeners>
<listener class-name="com.myproject.listeners.TestListener" />
</listeners>
<test name="LoginTests">
<classes>
<class name="com.myproject.tests.LoginTest" />
</classes>
</test>
</suite>
config.properties
baseUrl=https://example.com
username=defaultUser
password=defaultPassword
This structure leverages PageFactory for managing web elements, ensuring cleaner and more maintainable code.
Java Selenium Extended Project Structure
Here’s the extended project structure, including the requested files: README.md
, .github/CODEOWNERS
, and .github/pull_request_template.md
.
Updated Project Structure
MyAutomationProject/
├── .github/
│ └── workflows/
│ ├── nightly-build.yml # Nightly build pipeline
│ ├── push-build.yml # Build triggered on push
│ ├── CODEOWNERS # Code owners file
│ ├── pull_request_template.md # Pull request template
├── .gitignore # Files and folders to ignore in git
├── README.md # Project documentation
├── pom.xml # Maven configuration file
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── myproject/
│ │ │ ├── base/
│ │ │ │ ├── BaseTest.java # Base class for tests
│ │ │ │ └── DriverFactory.java # Manages WebDriver instances
│ │ │ ├── config/
│ │ │ │ └── ConfigReader.java # Reads configuration files
│ │ │ ├── pages/
│ │ │ │ ├── LoginPage.java # Login Page with PageFactory
│ │ │ │ └── DashboardPage.java # Dashboard Page with PageFactory
│ │ │ └── utils/
│ │ │ ├── TestUtils.java # Shared utility methods
│ │ │ └── WaitUtils.java # Explicit wait utility
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── myproject/
│ │ ├── tests/
│ │ │ ├── LoginTest.java # Test cases for Login
│ │ │ └── RegressionSuite.java # Regression Test Suite
│ │ ├── listeners/
│ │ │ └── TestListener.java # TestNG listener implementation
│ │ └── data/
│ │ └── TestDataProvider.java # Data provider for tests
│ └── resources/
│ ├── testng.xml # TestNG suite configuration
│ └── config.properties # Configuration properties
└── target/ # Maven build output
Examples of Added Files
README.md
# MyAutomationProject
## Overview
This project is a Selenium-based automation framework built with Java, TestNG, and Maven. It follows the Page Object Model (POM) with PageFactory for a clean and maintainable design.
## Features
- Automated browser testing with Selenium.
- Page Object Model with PageFactory.
- Test execution and reporting using TestNG.
- Continuous Integration using GitHub Actions (nightly builds and push-triggered builds).
## Project Structure
MyAutomationProject/ ├── .github/ ├── src/ ├── pom.xml ├── README.md ├── .gitignore
## Prerequisites
- Java 11 or higher.
- Maven installed.
- WebDriver binaries managed using WebDriverManager.
## How to Run Tests
1. Clone the repository.
2. Navigate to the project root.
3. Execute:
```bash
mvn test
Continuous Integration
- Nightly builds configured in
.github/workflows/nightly-build.yml
. - Builds triggered on each push to the
main
branch in.github/workflows/push-build.yml
.
Contributing
- Fork the repository.
- Create a new branch for your feature.
- Commit your changes.
- Submit a pull request (PR).
---
#### **`.github/CODEOWNERS`**
```plaintext
# Code owners file
# Specify individuals or teams responsible for specific files or directories.
# Format: path @github-username
# Owners for all files
* @owner1 @owner2
# Owners for specific folders
.github/ @ci-team
src/main/ @dev-team
src/test/ @qa-team
.github/pull_request_template.md
# Pull Request Template
## Description
- Please include a summary of the changes and the related issue this PR addresses.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Checklist
- [ ] Code follows the coding standards and guidelines.
- [ ] Tests have been added and pass locally.
- [ ] Documentation has been updated (if applicable).
## Related Issues
- Resolves #[issue-number]
## Screenshots (if applicable)
Include screenshots for UI-related changes.
## Additional Notes
Provide any additional context or details here.
How These Files Work
README.md
:- Provides an overview of the project, instructions for running tests, and contribution guidelines.
.github/CODEOWNERS
:- Defines ownership for code reviews. Specific users or teams are automatically assigned as reviewers for changes to designated files or directories.
.github/pull_request_template.md
:- A standardized template that contributors fill out when submitting pull requests.
Summary of Enhancements
- CI/CD Pipelines:
- Nightly and push-triggered builds in
.github/workflows/
.
- Nightly and push-triggered builds in
- Code Ownership:
- Ensures clear responsibilities using
.github/CODEOWNERS
.
- Ensures clear responsibilities using
- Pull Request Template:
- Simplifies and standardizes the PR process.
This setup fosters better collaboration and ensures a well-documented, maintainable project.