Automation testing is a software testing technique that executes test cases using automated tools and scripts, rather than manually. The goal is to perform repetitive tests, regression tests, and complex data-driven tests efficiently and accurately, leading to faster feedback and improved software quality.
A test automation framework is a set of guidelines, rules, and best practices for creating and designing test cases. It provides a structured approach to automation, leading to higher reusability, maintainability, and efficiency.
-- Example of Page Object Model Structure (conceptual)
// LoginPage.java
public class LoginPage {
private WebDriver driver;
// Locators
By usernameField = By.id("username");
By passwordField = By.id("password");
By loginButton = By.id("loginButton");
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
// Actions
public void enterUsername(String username) {
driver.findElement(usernameField).sendKeys(username);
}
public void enterPassword(String password) {
driver.findElement(passwordField).sendKeys(password);
}
public void clickLoginButton() {
driver.findElement(loginButton).click();
}
public DashboardPage login(String username, String password) {
enterUsername(username);
enterPassword(password);
clickLoginButton();
return new DashboardPage(driver);
}
}
// LoginTest.java
public class LoginTest {
WebDriver driver;
LoginPage loginPage;
@BeforeMethod
public void setup() {
// Initialize WebDriver
driver = new ChromeDriver(); // Or FirefoxDriver, etc.
driver.get("http://your-app-url.com/login");
loginPage = new LoginPage(driver);
}
@Test
public void testValidLogin() {
DashboardPage dashboard = loginPage.login("validUser", "validPassword");
Assert.assertTrue(dashboard.isDashboardLoaded());
}
@AfterMethod
public void tearDown() {
driver.quit();
}
}
Automation can be applied to various testing types across different layers of an application.
This section covers popular tools for different types of automation testing, along with example test scripts.
Selenium WebDriver is an open-source framework for automating web browsers. It supports multiple programming languages (Java, Python, C#, Ruby, JavaScript) and various browsers (Chrome, Firefox, Edge, Safari).
# Install Selenium
pip install selenium
# Download WebDriver for your browser (e.g., ChromeDriver)
# Add it to your system PATH or specify its location in the script.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import time
def test_Google Search():
# Path to your ChromeDriver (if not in PATH)
# service = Service(executable_path='/path/to/chromedriver')
# options = Options()
# driver = webdriver.Chrome(service=service, options=options)
# Simplified initialization if chromedriver is in PATH or using WebDriver Manager
driver = webdriver.Chrome()
try:
driver.get("https://www.google.com")
driver.maximize_window()
time.sleep(2) # Wait for page to load (not ideal, use explicit waits)
# Find the search input field by its name attribute
search_box = driver.find_element(By.NAME, "q")
# Type "Selenium Python tutorial" into the search box
search_box.send_keys("Selenium Python tutorial")
# Press Enter
search_box.send_keys(Keys.RETURN)
time.sleep(3) # Wait for search results to load
# Verify that the title of the page contains "Selenium Python tutorial"
assert "Selenium Python tutorial" in driver.title
print(f"Test Passed: Page title contains 'Selenium Python tutorial'. Current title: {driver.title}")
except Exception as e:
print(f"Test Failed: {e}")
# Optional: Take a screenshot on failure
driver.save_screenshot("Google Search_failure.png")
finally:
driver.quit() # Close the browser
if __name__ == "__main__":
test_Google Search()
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
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 LoginTest {
WebDriver driver;
@BeforeMethod
public void setup() {
WebDriverManager.chromedriver().setup(); // Automatically downloads and sets up ChromeDriver
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://example.com/login"); // Replace with your app's login URL
}
@Test
public void testSuccessfulLogin() {
// Find username field and enter value
WebElement usernameField = driver.findElement(By.id("username"));
usernameField.sendKeys("testuser");
// Find password field and enter value
WebElement passwordField = driver.id("password");
passwordField.sendKeys("password123");
// Find login button and click
WebElement loginButton = driver.findElement(By.xpath("//button[text()='Login']"));
loginButton.click();
// Verify successful login by checking for a dashboard element or URL change
// This is a placeholder; replace with actual dashboard element locator
Assert.assertTrue(driver.getCurrentUrl().contains("/dashboard"), "Login failed: Not redirected to dashboard");
WebElement welcomeMessage = driver.findElement(By.cssSelector(".welcome-message"));
Assert.assertTrue(welcomeMessage.isDisplayed() && welcomeMessage.getText().contains("Welcome, testuser"), "Welcome message not displayed or incorrect.");
System.out.println("Login Test Passed: User successfully logged in.");
}
@Test
public void testInvalidLogin() {
WebElement usernameField = driver.findElement(By.id("username"));
usernameField.sendKeys("invaliduser");
WebElement passwordField = driver.findElement(By.id("password"));
passwordField.sendKeys("wrongpassword");
WebElement loginButton = driver.findElement(By.xpath("//button[text()='Login']"));
loginButton.click();
// Verify error message
WebElement errorMessage = driver.findElement(By.id("error-message")); // Replace with actual error message locator
Assert.assertTrue(errorMessage.isDisplayed(), "Error message not displayed for invalid login.");
Assert.assertTrue(errorMessage.getText().contains("Invalid credentials"), "Incorrect error message for invalid login.");
System.out.println("Invalid Login Test Passed: Correct error message displayed.");
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Cypress is a modern, fast, and developer-friendly testing framework for web applications. It runs directly in the browser and provides real-time reloads and debugging.
# Install Node.js and npm first
npm install cypress --save-dev
npx cypress open # To open the Cypress Test Runner
// cypress/e2e/form_submission.cy.js
describe('Form Submission Tests', () => {
beforeEach(() => {
cy.visit('http://your-app-url.com/contact'); // Replace with your app's form URL
});
it('should submit the form successfully with valid data', () => {
cy.get('#name').type('Jane Doe');
cy.get('#email').type('jane.doe@example.com');
cy.get('#message').type('This is a test message.');
cy.get('button[type="submit"]').click();
// Assert success message or redirection
cy.get('.success-message').should('be.visible').and('contain.text', 'Thank you for your message!');
cy.url().should('include', '/success'); // Optional: check for URL change
});
it('should display error messages for empty required fields', () => {
cy.get('button[type="submit"]').click(); // Click without filling fields
cy.get('#name-error').should('be.visible').and('contain.text', 'Name is required');
cy.get('#email-error').should('be.visible').and('contain.text', 'Email is required');
cy.get('.success-message').should('not.exist'); // Ensure no success message
});
it('should display error for invalid email format', () => {
cy.get('#name').type('Jane Doe');
cy.get('#email').type('invalid-email'); // Invalid email
cy.get('#message').type('This is a test message.');
cy.get('button[type="submit"]').click();
cy.get('#email-error').should('be.visible').and('contain.text', 'Invalid email format');
cy.get('.success-message').should('not.exist');
});
});
Playwright is another powerful open-source framework from Microsoft for reliable end-to-end testing across browsers, platforms, and devices. It supports multiple languages and offers auto-waiting, parallel execution, and strong selectors.
npm init playwright@latest # Follow prompts
# Or for existing project:
npm install --save-dev @playwright/test
// tests/todo.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Todo App Functionality', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc'); // Replace with your todo app URL
});
test('should allow me to add todo items', async ({ page }) => {
await page.locator('.new-todo').fill('buy some cheese');
await page.locator('.new-todo').press('Enter');
await page.locator('.new-todo').fill('buy some milk');
await page.locator('.new-todo').press('Enter');
await expect(page.locator('.todo-list li')).toHaveCount(2);
await expect(page.locator('.todo-list li').nth(0)).toHaveText('buy some cheese');
await expect(page.locator('.todo-list li').nth(1)).toHaveText('buy some milk');
});
test('should clear completed items', async ({ page }) => {
// Add items
await page.locator('.new-todo').fill('walk the dog');
await page.locator('.new-todo').press('Enter');
await page.locator('.new-todo').fill('feed the cat');
await page.locator('.new-todo').press('Enter');
// Mark one as complete
await page.locator('.todo-list li .toggle').first().click();
// Click clear completed
await page.locator('.clear-completed').click();
await expect(page.locator('.todo-list li')).toHaveCount(1);
await expect(page.locator('.todo-list li')).toHaveText('feed the cat');
});
});
API testing focuses on the business logic layer of the application, ensuring that APIs function correctly, securely, and performantly.
Postman is a popular tool for building, testing, and documenting APIs. It allows for manual execution of API requests and writing automated tests.
// Check status code is 200 OK
pm.test("Status code is 200 OK", function () {
pm.response.to.have.status(200);
});
// Parse JSON response and check a specific value
pm.test("Response body contains correct user ID", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.id).to.eql(123); // Assuming 'id' is a field in the JSON
});
// Check if a header exists
pm.test("Content-Type header is present", function () {
pm.response.to.have.header("Content-Type");
});
// Check for response time
pm.test("Response time is less than 200ms", function () {
pm.expect(pm.response.responseTime).to.be.below(200);
});
Rest-Assured is a Java library for testing RESTful APIs. It's widely used due to its fluent interface and powerful assertion capabilities.
// Maven dependency (pom.xml)
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.8.0</version>
<scope>test</scope>
</dependency>
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*; // For Hamcrest matchers
public class UserApiTest {
@BeforeClass
public void setup() {
RestAssured.baseURI = "https://reqres.in"; // A public API for testing
RestAssured.basePath = "/api";
}
@Test
public void testGetSingleUser() {
Response response = given()
.when()
.get("/users/2") // Endpoint to get user with ID 2
.then()
.statusCode(200) // Assert HTTP status code
.body("data.id", equalTo(2)) // Assert 'id' field in 'data' object
.body("data.first_name", equalTo("Janet")) // Assert 'first_name'
.body("data.last_name", equalTo("Weaver"))
.body("data.email", notNullValue()) // Assert 'email' is not null
.extract().response(); // Extract response object for further assertions
// More detailed assertions using TestNG
String email = response.jsonPath().getString("data.email");
Assert.assertEquals(email, "janet.weaver@reqres.in", "Email does not match");
System.out.println("User data: " + response.asString());
}
@Test
public void testCreateUser() {
String requestBody = "{ \"name\": \"morpheus\", \"job\": \"leader\" }";
Response response = given()
.header("Content-Type", "application/json")
.body(requestBody)
.when()
.post("/users")
.then()
.statusCode(201) // Assert HTTP status code for creation
.body("name", equalTo("morpheus"))
.body("job", equalTo("leader"))
.body("id", notNullValue()) // Assert 'id' is generated
.body("createdAt", notNullValue()) // Assert 'createdAt' timestamp
.extract().response();
System.out.println("Created user response: " + response.asString());
}
@Test
public void testUserNotFound() {
given()
.when()
.get("/users/999") // Non-existent user ID
.then()
.statusCode(404) // Assert 404 Not Found
.body(isEmptyOrNullString()); // Assert response body is empty or null
}
}
Appium is an open-source tool for automating native, hybrid, and mobile web applications. It supports iOS, Android, and Windows desktop platforms.
# Install Node.js, npm, Java (JDK), Android SDK (for Android), Xcode (for iOS)
npm install -g appium
npm install -g appium-doctor # To check setup
appium-doctor
# Install Appium client libraries for your language (e.g., Python, Java)
pip install Appium-Python-Client # For Python
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def test_android_app_login():
# Desired Capabilities - specify app, device, and automation details
desired_caps = {
"platformName": "Android",
"deviceName": "emulator-5554", # Replace with your emulator/device name
"appPackage": "com.example.myapp", # Replace with your app's package
"appActivity": "com.example.myapp.MainActivity", # Replace with your app's main activity
"automationName": "UiAutomator2",
"noReset": True # Don't reset app state between sessions
}
# Initialize Appium driver
driver = webdriver.Remote("http://localhost:4723/wd/hub", options=UiAutomator2Options().load_capabilities(desired_caps))
wait = WebDriverWait(driver, 30) # Explicit wait
try:
print("App launched successfully!")
# Example: Locate and interact with login elements
username_field = wait.until(EC.presence_of_element_located((AppiumBy.ID, "com.example.myapp:id/username_edittext")))
username_field.send_keys("testuser")
print("Entered username.")
password_field = driver.find_element(AppiumBy.ID, "com.example.myapp:id/password_edittext")
password_field.send_keys("password123")
print("Entered password.")
login_button = driver.find_element(AppiumBy.ID, "com.example.myapp:id/login_button")
login_button.click()
print("Clicked login button.")
# Verify successful login (e.g., check for dashboard element)
welcome_text = wait.until(EC.presence_of_element_located((AppiumBy.ID, "com.example.myapp:id/welcome_message")))
assert "Welcome" in welcome_text.text
print("Login successful! Welcome message found.")
except Exception as e:
print(f"Test Failed: {e}")
driver.save_screenshot("mobile_login_failure.png")
finally:
driver.quit()
print("Driver closed.")
if __name__ == "__main__":
test_android_app_login()
Apache JMeter is an open-source tool designed to load test functional behavior and measure performance. It's primarily used for web applications, but can test other protocols as well.
Test Plan
├── Thread Group (e.g., 100 Users, 10s Ramp-up, 5 Loops)
│ ├── HTTP Request Defaults (e.g., Server Name: example.com, Port: 80)
│ ├── HTTP Cookie Manager (to handle sessions)
│ ├── Login Transaction Controller
│ │ ├── HTTP Request: Login (POST /login)
│ │ │ ├── Parameters: username=${USERNAME}, password=${PASSWORD}
│ │ │ └── Response Assertions: Check for "Login Successful" in response
│ │ └── JSON Extractor: Extract Auth Token
│ ├── Browse Products Transaction Controller
│ │ ├── HTTP Request: Home Page (GET /)
│ │ ├── HTTP Request: Products Page (GET /products)
│ │ └── Regular Expression Extractor: Extract Product IDs
│ ├── Add to Cart Transaction Controller
│ │ ├── HTTP Request: Add Product (POST /cart/add)
│ │ │ ├── Parameters: product_id=${PRODUCT_ID}, quantity=1
│ │ │ └── Headers: Authorization: Bearer ${AUTH_TOKEN}
│ │ └── Response Assertions: Check for "Item added"
│ └── View Results Tree (Listener - for debugging)
│ └── Summary Report (Listener - for aggregated results)
└── CSV Data Set Config (e.g., users.csv with USERNAME,PASSWORD columns)
Continuous Integration (CI) and Continuous Delivery/Deployment (CD) pipelines automate the entire software delivery process, and test automation is a critical component.
Jenkins is a popular open-source automation server used for building, deploying, and automating any project. It can orchestrate test automation execution.
// Jenkinsfile
pipeline {
agent any
environment {
// Define environment variables
BROWSER = 'chrome'
TEST_ENV_URL = 'http://staging.yourapp.com'
}
stages {
stage('Checkout') {
steps {
git 'https://github.com/your-repo/your-project.git' // Replace with your repo
}
}
stage('Build') {
steps {
// Example for a Node.js project
sh 'npm install'
sh 'npm run build' // If a build step is required
}
}
stage('Run Unit Tests') {
steps {
// Example for Node.js (Jest) or Java (Maven Surefire)
sh 'npm test -- --ci --json --outputFile=unit-test-results.json' // Save results for reporting
}
post {
always {
junit '**/unit-test-results.xml' // Publish JUnit results
}
}
}
stage('Run API Tests') {
when {
// Only run API tests if unit tests pass
expression { currentBuild.currentResult == 'SUCCESS' }
}
steps {
// Example for Java with Rest-Assured & Maven
sh 'mvn test -Dtest=UserApiTest'
}
post {
always {
junit '**/target/surefire-reports/*.xml' // Publish Maven test results
}
}
}
stage('Deploy to Staging') {
steps {
echo 'Deploying application to staging environment...'
// Add deployment commands (e.g., Docker commands, Ansible playbooks)
sh 'docker-compose up -d --build' // Example for Docker
}
}
stage('Run UI Automation Tests') {
when {
// Only run UI tests if deployment to staging is successful
expression { currentBuild.currentResult == 'SUCCESS' }
}
steps {
echo 'Running end-to-end UI tests with Playwright...'
// Example for Playwright/Cypress
sh 'npx playwright test' // Or 'npx cypress run'
}
post {
always {
junit '**/test-results/**/*.xml' // Playwright/Cypress can output JUnit XML
}
}
}
stage('Publish Test Reports') {
steps {
// Use plugins like HTML Publisher to display custom HTML reports (e.g., Allure Report)
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'playwright-report', // Or 'cypress/reports', 'allure-results'
reportFiles: 'index.html',
reportName: 'Automation Test Report'
])
}
}
}
post {
always {
cleanWs() // Clean up workspace
}
success {
echo 'Pipeline finished successfully!'
// Add notifications (e.g., Slack, Email)
}
failure {
echo 'Pipeline failed!'
// Add failure notifications, attach logs/screenshots
}
}
}
Tools that integrate with automation frameworks to provide centralized test case management, execution tracking, and comprehensive reporting.
# Example: Import JUnit XML results from Playwright into Xray via Jira API
# (Requires Xray credentials and API endpoint)
# curl -H "Content-Type: application/xml" -X POST -u "username:password" \
# "https://your-jira-instance/rest/raven/1.0/import/execution/junit?projectKey=YOUR_PROJECT" \
# --data-binary "@path/to/junit_report.xml"
allure-playwright
, allure-selenium-java
, pytest-allure-adaptor
).# Install Allure Commandline (e.g., via npm)
npm install -g allure-commandline --save-dev
# Generate the report from results
allure generate allure-results --clean -o allure-report
# Open the report in your browser
allure open allure-report
WebDriverWait
in Selenium) instead of static waits (time.sleep()
) to handle dynamic elements and avoid flaky tests.Automation testing is a highly in-demand skill in the software industry. It offers a rewarding career path with continuous learning opportunities.
Junior Automation Engineer -> Automation Engineer -> Senior Automation Engineer -> Lead QA Automation Engineer -> QA Architect / SDET (Software Development Engineer in Test).