Manual API Testing with Postman API testing is crucial to ensure that APIs are functioning correctly and as expected. Postman is one of the most popular tools for manual API testing due to its ease of use and flexibility. Here’s how you can manually test an API with Postman:
- Set Up Postman
- Download and install Postman.
- Create a new request by selecting the appropriate HTTP method (GET, POST, PUT, DELETE).
- Enter the endpoint URL, headers, parameters, and body (if applicable).
- Make the API Request
- Hit the “Send” button and review the response, ensuring that the status code and response body match expectations.
- Validate response headers, body structure, and values to ensure correctness.
- Testing Common API Assertions
- Status Codes: Ensure the correct HTTP status code is returned (e.g., 200 for success, 404 for not found).
- Response Time: Verify that the API responds within an acceptable timeframe.
- Response Structure: Confirm the body contains the correct data and structure (e.g., JSON, XML).
Automated API Testing with Newman Once you’ve manually tested your API, you can automate the tests using Newman, the command-line tool that runs Postman collections.
- Export Postman Collection
- After creating and testing your API requests, export your collection to a JSON file in Postman.
- Install Newman
- Install Newman globally using npm:
npm install -g newman
- Install Newman globally using npm:
- Run Tests with Newman
- Run the collection in your CI pipeline or locally:
newman run /path/to/your/collection.json
- You can specify environments, data files, and other options to customize the test run.
- Run the collection in your CI pipeline or locally:
- Integrating with CI/CD
- Integrate Newman into your CI/CD pipeline (e.g., Jenkins, GitHub Actions) to run automated API tests after each deployment.
API Testing with Selenium, Cypress, and Playwright (Happy and Sad Paths)
API Testing with Selenium Selenium is primarily used for UI testing, but it can also be leveraged for API testing by making HTTP requests and verifying responses. Here’s a simple scenario for both happy and sad paths:
- Happy Path: Test that a correct request returns the expected response.
- Sad Path: Simulate invalid requests to ensure the API returns the correct error codes (e.g., 400 or 404).
Example Scenario:
- Happy Path Test (GET request)
- Send a GET request to the endpoint
/api/v1/users
. - Expected Result: Status code 200 and a JSON body with a list of users.
- Send a GET request to the endpoint
- Sad Path Test (GET request)
- Send a GET request to the endpoint
/api/v1/users/9999999
(non-existent user). - Expected Result: Status code 404 and an error message stating the user doesn’t exist.
- Send a GET request to the endpoint
API Testing with Cypress Cypress is another tool primarily designed for end-to-end testing but can also be used for API requests. Cypress makes it easy to test both happy and sad paths using its cy.request()
command.
Example Scenario:
- Happy Path Test (POST request)
- Send a POST request to
/api/v1/users
with a valid JSON body:{ "name": "John Doe", "email": "john@example.com" }
- Expected Result: Status code 201 and a JSON response with the created user’s details.
- Send a POST request to
- Sad Path Test (POST request)
- Send a POST request to
/api/v1/users
with missing or invalid data (e.g., noemail
). - Expected Result: Status code 400 and an error message indicating the validation failure.
- Send a POST request to
API Testing with Playwright Playwright is another powerful tool that can handle API requests in addition to UI tests. Its approach to API testing is similar to Selenium and Cypress but with added performance benefits.
- Happy Path Test (PUT request)
- Send a PUT request to update an existing user’s details, e.g.,
/api/v1/users/12345
with valid data. - Expected Result: Status code 200 and updated user data in the response.
- Send a PUT request to update an existing user’s details, e.g.,
- Sad Path Test (PUT request)
- Send a PUT request to
/api/v1/users/12345
with invalid or incomplete data. - Expected Result: Status code 400 and an error message for invalid data.
- Send a PUT request to
Combined UI and API Testing: Manual and Automated (Happy and Sad Paths)
Manual Combined UI and API Testing
For manual testing, we will simulate a user action (e.g., login) and validate both the UI behavior and API response.
Test Scenario 1 (Happy Path):
- UI Interaction:
- The user enters valid credentials and clicks the “Login” button.
- API Verification:
- The API should return a success response with status code
200
and relevant user data.
- The API should return a success response with status code
Example of UI Interaction (Login Form):
- Fill in the username and password fields in the web UI, click the submit button.
Example API Verification:
- Verify the API response using Postman or any tool of choice.
Expected Result:
- The user is logged in successfully, and the API returns the correct user data.
Test Scenario 2 (Sad Path):
- UI Interaction:
- The user enters invalid credentials and clicks the “Login” button.
- API Verification:
- The API should return an error with status code
401
(Unauthorized) and an error message.
- The API should return an error with status code
Example of UI Interaction (Login Form):
- Enter an incorrect username or password in the UI.
Example API Verification:
- The API should respond with a
401 Unauthorized
status.
Expected Result:
- The login fails with an appropriate error message shown on the UI, and the API returns a proper error response.
Automated Combined UI and API Testing
Let’s now move to automated testing, where we can perform both UI actions and API calls within a test script.
1. Automated Combined UI and API Testing with Selenium
For Selenium, we’ll use the WebDriver
to interact with the UI and also use libraries like HttpURLConnection
or RestAssured
to call the API.
Example:
Happy Path:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import io.restassured.RestAssured;
import io.restassured.response.Response;
public class CombinedUITest {
public static void main(String[] args) {
// Set up WebDriver and open the login page
WebDriver driver = new ChromeDriver();
driver.get("http://yourapp.com/login");
// Enter valid credentials in the login form
driver.findElement(By.id("username")).sendKeys("validUser");
driver.findElement(By.id("password")).sendKeys("validPassword");
driver.findElement(By.id("loginButton")).click();
// Verify that the UI navigates to the homepage
Assert.assertTrue(driver.getTitle().contains("Home"));
// API Request to verify the user
Response response = RestAssured.given()
.header("Authorization", "Bearer validToken")
.get("http://yourapp.com/api/v1/users/validUser");
// Assert the API response status and body
Assert.assertEquals(response.statusCode(), 200);
Assert.assertTrue(response.body().asString().contains("validUser"));
driver.quit();
}
}
Sad Path:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import io.restassured.RestAssured;
import io.restassured.response.Response;
public class CombinedUITest {
public static void main(String[] args) {
// Set up WebDriver and open the login page
WebDriver driver = new ChromeDriver();
driver.get("http://yourapp.com/login");
// Enter invalid credentials in the login form
driver.findElement(By.id("username")).sendKeys("invalidUser");
driver.findElement(By.id("password")).sendKeys("invalidPassword");
driver.findElement(By.id("loginButton")).click();
// Verify the error message in the UI
Assert.assertTrue(driver.findElement(By.id("errorMessage")).getText().contains("Invalid credentials"));
// API Request to verify failed login
Response response = RestAssured.given()
.get("http://yourapp.com/api/v1/users/invalidUser");
// Assert that the API returns 404 error
Assert.assertEquals(response.statusCode(), 404);
driver.quit();
}
}
2. Automated Combined UI and API Testing with Cypress
Cypress allows easy interaction with both the UI and API. Here’s an example using Cypress.
Happy Path:
describe('Login UI + API Test', () => {
it('should log in and verify the user via API', () => {
// Visit the login page
cy.visit('http://yourapp.com/login');
// Interact with the login form
cy.get('#username').type('validUser');
cy.get('#password').type('validPassword');
cy.get('#loginButton').click();
// Verify UI navigates to home page
cy.url().should('include', '/home');
// API Request to verify the user
cy.request({
method: 'GET',
url: 'http://yourapp.com/api/v1/users/validUser',
headers: {
'Authorization': 'Bearer validToken'
}
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body).to.include({ username: 'validUser' });
});
});
});
Sad Path:
describe('Login UI + API Test', () => {
it('should show error on invalid credentials and verify via API', () => {
// Visit the login page
cy.visit('http://yourapp.com/login');
// Interact with the login form
cy.get('#username').type('invalidUser');
cy.get('#password').type('invalidPassword');
cy.get('#loginButton').click();
// Verify UI displays error message
cy.get('#errorMessage').should('contain.text', 'Invalid credentials');
// API Request to verify failed login
cy.request({
method: 'GET',
url: 'http://yourapp.com/api/v1/users/invalidUser',
failOnStatusCode: false // to prevent Cypress from failing the test on 404
}).then((response) => {
expect(response.status).to.eq(404);
});
});
});
3. Automated Combined UI and API Testing with Playwright
Playwright offers robust support for API calls in addition to UI tests.
Happy Path:
const { chromium } = require('playwright');
const fetch = require('node-fetch');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
// Visit the login page
await page.goto('http://yourapp.com/login');
// Fill the login form
await page.fill('#username', 'validUser');
await page.fill('#password', 'validPassword');
await page.click('#loginButton');
// Verify the UI navigates to the homepage
await page.waitForSelector('text=Welcome Home');
// API Request to verify the user
const response = await fetch('http://yourapp.com/api/v1/users/validUser', {
headers: { 'Authorization': 'Bearer validToken' }
});
const body = await response.json();
console.log(body);
console.assert(response.status === 200, 'Expected status code 200');
console.assert(body.username === 'validUser', 'Expected user to be validUser');
await browser.close();
})();
Sad Path:
const { chromium } = require('playwright');
const fetch = require('node-fetch');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
// Visit the login page
await page.goto('http://yourapp.com/login');
// Fill the login form with invalid credentials
await page.fill('#username', 'invalidUser');
await page.fill('#password', 'invalidPassword');
await page.click('#loginButton');
// Verify the error message on the UI
const errorMessage = await page.textContent('#errorMessage');
console.assert(errorMessage.includes('Invalid credentials'), 'Expected error message for invalid login');
// API Request to verify failed login
const response = await fetch('http://yourapp.com/api/v1/users/invalidUser');
console.assert(response.status === 404, 'Expected status code 404');
await browser.close();
})();
Conclusion By integrating both UI and API testing (manual and automated) with proper handling of happy and sad paths, you can ensure a seamless user experience, reliable backend functionality, and a robust, well-tested application.
To know how I expanded the happy and sad paths for greater testing coverage check this post out: The Happy and Sad Path: Key Concepts in QA Testing.