Advanced API Test Scenarios

To take API testing to the next level, you need to create comprehensive test scenarios based on real-world use cases. Here are examples and tips for createing end-to-end API test scenarios that follow a sequence:Advanced Test Scenarios for GET Services

Advanced Test Scenarios for GET Services

  1. Basic Functionality Tests

    Does it return the correct HTTP status code? (200, 404, 403, etc.)

    Is the response schema in the expected format?

    Are all required fields present in the response?

    Do pagination, filtering, and sorting parameters work correctly?

  2. Boundary Value Tests

    Does the API respond correctly when requested with the maximum record count?

    How does the system behave with very large/small ID values?

    Are unused parameters ignored?

  3. Negative Test Scenarios

    Does it return 401 when a request is made with incorrect authentication?

    Does it return 403 when a request is made to resources without access permission?

    Does it return a proper 404 response for non-existent resources?

    Does it return an appropriate error message with an expired token?

  4. Performance Edge-Case Tests

    How does the API behave when returning a very large dataset?

    Does rate limiting work correctly with fast and repeated GET requests?

    Does the timeout policy work in high latency situations?

Advanced Test Scenarios for POST Services

  1. Functionality Tests

    Is a POST operation successful with valid data and returns 201 Created?

    Is the location of the created resource returned in the Location header?

    Is the information of the returned resource correct and complete?

  2. Data Validation Tests

    Does it return an appropriate 400 error when a request is made with missing required fields?

    Is the error message clear when a request is made with an invalid data format?

    How does the system behave with a very large payload?

    Does it return the correct validation error with incorrect data types?

  3. Idempotence Checks

    Does the system detect when the same POST request is sent twice?

    Does it return an appropriate error code when attempting to create the same resource again?

  4. Business Rule Tests

    Does it return a business rule error when data that violates business rules is sent (e.g., an order with a past date)?

    Are references to related resources correctly checked? (e.g., non-existent customer ID)

Advanced Test Scenarios for PUT Services

  1. Update Functionality Tests

    Does it return the correct HTTP status code after successful update (200 OK)?

    Does it return 404 when attempting to update a non-existent resource?

    Is the updated resource information correctly reflected in the response?

    Are all fields properly updated as specified in the request?

  2. Partial Update Validation

    Does it correctly handle updating only specified fields while preserving others?

    Does it validate the data types and formats of updated fields?

    Is the response consistent with the updated state of the resource?

  3. Concurrency Control Tests

    Does it handle ETag or Last-Modified headers correctly to prevent lost updates?

    Does it return 412 Precondition Failed when the resource has been modified by another client?

    How does it handle simultaneous update requests to the same resource?

  4. Idempotence Verification

    Is the PUT operation truly idempotent (multiple identical requests have the same effect)?

    Does repeating the same request result in the same final state without side effects?

Advanced Test Scenarios for PATCH Services

  1. Partial Update Tests

    Does it correctly update only the specified fields?

    Does it return 200 OK or 204 No Content after a successful patch?

    Does the response accurately reflect the changes made?

    Are JSON Patch or JSON Merge Patch formats handled correctly?

  2. Schema Validation

    Does it validate the patch document structure before applying changes?

    Does it return 400 Bad Request for malformed patch documents?

    Are validation errors clearly described in the response?

  3. Patch Operation Tests

    Are add, remove, replace, move, copy, and test operations handled correctly?

    Does it handle path references properly, including nested properties?

    How does it behave when a specified path doesn't exist?

  4. State Transition Tests

    Does it enforce business rules when transitioning states via PATCH?

    Are invalid state transitions properly rejected with appropriate error messages?

Advanced Test Scenarios for DELETE Services

  1. Resource Removal Tests

    Does it return 204 No Content or 200 OK after successful deletion?

    Does it return 404 Not Found when attempting to delete a non-existent resource?

    Is the resource truly removed and no longer accessible after deletion?

  2. Cascade Deletion Tests

    How does it handle dependent resources (cascade delete or prevent deletion)?

    Does it return 409 Conflict when deletion would violate constraints?

    Are child resources properly handled during parent resource deletion?

  3. Authorization Tests

    Does it verify proper authorization before allowing deletion?

    Does it return 403 Forbidden when attempting to delete resources without permission?

    Are ownership checks properly implemented for multi-tenant systems?

  4. Soft Delete vs Hard Delete Tests

    If implementing soft delete, is the resource properly marked as deleted but retained in the system?

    Are soft-deleted resources excluded from general queries?

    Can soft-deleted resources be restored properly?

Advanced Test Scenarios for HEAD Services

  1. Metadata Verification Tests

    Does it return the same headers as a GET request without the response body?

    Are Content-Length, Content-Type, and ETag headers accurate?

    Does it return proper status codes (200, 404, etc.) like the corresponding GET request?

  2. Cache Control Tests

    Are Cache-Control, Expires, and Last-Modified headers properly set?

    Does the ETag value change appropriately when the resource changes?

    Do conditional requests with If-None-Match or If-Modified-Since work correctly?

  3. Resource Existence Tests

    Can HEAD requests efficiently check for resource existence without transferring the entire body?

    Is the performance notably better than equivalent GET requests?

Advanced Test Scenarios for OPTIONS Services

  1. CORS Preflight Tests

    Does it properly respond to preflight requests with Access-Control-* headers?

    Are the allowed origins, methods, and headers correctly specified?

    Does it handle the Access-Control-Max-Age header correctly?

  2. API Capabilities Tests

    Does it accurately return the Allow header with all supported HTTP methods?

    For RESTful services, does it provide information about resource representation formats?

    Does it provide any API documentation links or additional information?

  3. API Version Tests

    Does it include API version information in headers?

    Are deprecated endpoints or features properly indicated?

E2E API Test Scenarios That Follow a Sequence

E-Commerce Order Flow Scenario

1. User Login and Token Acquisition
   - Send user credentials to POST /auth/login endpoint
   - Store the returned token and use it in the Authorization header for subsequent requests
   - ASSERTION: Status 200, token should be returned and in valid format

2. Query Product Catalog
   - Send a request to GET /products endpoint with the token
   - ASSERTION: Status 200, product list should be returned
   - Select one of the returned products and store the product ID

3. Query Product Detail
   - Send a request to GET /products/{product_id} endpoint with the product ID selected in the previous step
   - ASSERTION: Status 200, product details should be returned
   - ASSERTION: Stock status should be checked (stock > 0)

4. Add Product to Cart
   - Send a request to POST /cart/items endpoint with product ID and quantity information
   - ASSERTION: Status 201, cart summary should be returned
   - Store the returned cart ID

5. Verify Cart Contents
   - Send a request to GET /cart endpoint
   - ASSERTION: Status 200, cart contents should be returned
   - ASSERTION: Added product should be in the cart and quantity should be correct

6. Add Delivery Address
   - Send a request to POST /user/addresses endpoint with address information
   - ASSERTION: Status 201, address should be saved
   - Store the returned address ID

7. Create Order
   - Send a request to POST /orders endpoint with cart ID, address ID, and payment information
   - ASSERTION: Status 201, order should be created
   - Store the returned order ID

8. Check Order Status
   - Send a request to GET /orders/{order_id} endpoint
   - ASSERTION: Status 200, order details should be returned
   - ASSERTION: Order status should be "Processing"

9. (Optional) Cancel Order
   - Send a request to DELETE /orders/{order_id} endpoint
   - ASSERTION: Status 200, order should be canceled
   - Check the cancellation status of the order with GET

Banking Operations Scenario

1. Login and Token Acquisition
   - Send credentials to POST /auth/token endpoint
   - Store the returned access token and refresh token
   - ASSERTION: Status 200, tokens should be in valid format

2. List User Accounts
   - Send a request to GET /accounts endpoint with the token
   - ASSERTION: Status 200, account list should be returned
   - Select and store source account ID and target account ID from different accounts

3. Check Account Balance
   - Send a request to GET /accounts/{source_account_id}/balance endpoint
   - ASSERTION: Status 200, balance information should be returned
   - ASSERTION: Balance should be sufficient for transfer

4. Create Transfer Order
   - Send a request to POST /transfers endpoint with account IDs and amount information
   - ASSERTION: Status 202 (Accepted), transfer should be initiated
   - Store the returned transfer ID

5. Check Transfer Status
   - Send a request to GET /transfers/{transfer_id} endpoint
   - ASSERTION: Status 200, transfer status should be returned
   - ASSERTION: Transfer status should initially be "Processing"

6. Wait for Transfer Result (Polling)
   - Send requests to GET /transfers/{transfer_id} endpoint at regular intervals
   - ASSERTION: After a certain period of time, transfer status should be "Completed"

7. Check Balances After Transfer
   - Send a request to GET /accounts/{source_account_id}/balance endpoint
   - Send a request to GET /accounts/{target_account_id}/balance endpoint
   - ASSERTION: Source account balance should have decreased by the transfer amount
   - ASSERTION: Target account balance should have increased by the transfer amount

8. Check Transaction History
   - Send a request to GET /accounts/{source_account_id}/transactions endpoint
   - ASSERTION: Status 200, transaction list should be returned
   - ASSERTION: The transfer should appear in the transaction list

Tips for Advanced API Testing

1. Depth and Scope

  • Complete Business Flow: Test end-to-end business flows that reflect real usage scenarios.

  • Inter-Service Dependencies: Test interactions between microservices.

  • Edge Cases: Test not just the "happy path," but also the limits and error conditions of the system.

2. Test Data Management

  • Dynamic Data Generation: Dynamically generate data to be used in tests.

  • Test Database Synchronization: Automatically reset the test database or bring it to a known state.

  • Sensitive Test Data: Encrypt or mask test data to ensure security.

3. Test Automation Strategies

  • Parameter Extraction: Extract values from an API response and use them dynamically in subsequent API requests.
// Example Postman/Newman script
pm.test("Token obtained and stored", function() {
    var jsonData = pm.response.json();
    pm.environment.set("authToken", jsonData.token);
    pm.environment.set("userId", jsonData.userId);
});
  • Context Sharing: Share state and context between tests.
// Store data extracted from one test
pm.globals.set("productId", pm.response.json().items[0].id);

// Use in a different test
pm.request.url.path = `/products/${pm.globals.get("productId")}/details`;
  • Conditional Tests: Run different tests conditionally based on a value in an API response.
// Example: Different validations based on payment method
if (pm.response.json().paymentMethod === "credit_card") {
    pm.test("Credit card details should be validated", function() {
        // Credit card validations
    });
} else if (pm.response.json().paymentMethod === "bank_transfer") {
    pm.test("Bank transfer details should be validated", function() {
        // Bank transfer validations
    });
}

4. Verification Mechanisms

  • Before-After Verification: Verify by comparing the state before and after an operation.
// Store state before operation
pm.environment.set("previousBalance", pm.response.json().balance);

// Compare after operation
pm.test("Balance should be correctly decreased", function() {
    var previousBalance = parseFloat(pm.environment.get("previousBalance"));
    var currentBalance = pm.response.json().balance;
    var transferAmount = parseFloat(pm.environment.get("transferAmount"));

    pm.expect(currentBalance).to.eql(previousBalance - transferAmount);
});
  • Database Verification: Verify by checking the database state after API operations.

  • Business Rules Verification: Check if API behavior complies with business rules.

5. Test Reporting and Monitoring

  • Detailed Logging: Keep detailed logs before and after each request to facilitate debugging.

  • Test Reports: Create comprehensive test reports to visualize test results.

  • CI/CD Integration: Integrate tests into CI/CD pipelines for automatic execution.

Example: E2E API Test Approach with Sequential Services

Below is a detailed example showing how API calls that follow each other can be turned into a test scenario that tests a real usage scenario:

// 1. Login and get token
pm.test("Login should be successful and return a token", function() {
    pm.response.to.have.status(200);
    var jsonData = pm.response.json();

    pm.expect(jsonData).to.have.property('token');
    pm.expect(jsonData.token).to.be.a('string').and.to.have.lengthOf.at.least(20);

    // Save token to environment variable
    pm.environment.set("authToken", jsonData.token);

    // Store user ID
    pm.environment.set("userId", jsonData.userId);
});

// 2. List accounts belonging to the user
pm.test("User accounts should be successfully listed", function() {
    pm.response.to.have.status(200);
    var jsonData = pm.response.json();

    pm.expect(jsonData).to.be.an('object');
    pm.expect(jsonData.accounts).to.be.an('array').and.to.have.lengthOf.at.least(1);

    // Select and store source account for transfer
    var sourceAccount = jsonData.accounts.find(acc => acc.type === "CHECKING" && acc.balance > 100);
    pm.environment.set("sourceAccountId", sourceAccount.id);
    pm.environment.set("sourceAccountBalance", sourceAccount.balance);

    // Select and store target account for transfer
    var targetAccount = jsonData.accounts.find(acc => acc.id !== sourceAccount.id);
    pm.environment.set("targetAccountId", targetAccount.id);
    pm.environment.set("targetAccountBalance", targetAccount.balance);
});

// 3. Create transfer operation
pm.test("Transfer should be successfully created", function() {
    pm.response.to.have.status(201);
    var jsonData = pm.response.json();

    pm.expect(jsonData).to.have.property('transferId');
    pm.expect(jsonData).to.have.property('status', 'PENDING');

    // Store transfer ID
    pm.environment.set("transferId", jsonData.transferId);

    // Store transfer amount
    pm.environment.set("transferAmount", request.data.amount);
});

// 4. Check transfer status
pm.test("Transfer status should be correct", function() {
    pm.response.to.have.status(200);
    var jsonData = pm.response.json();

    pm.expect(jsonData).to.have.property('transferId', pm.environment.get("transferId"));
    pm.expect(jsonData).to.have.property('status');

    // If transfer is completed, check balance
    if (jsonData.status === "COMPLETED") {
        pm.environment.set("transferCompleted", true);
    } else {
        console.log("Transfer still in process, status: " + jsonData.status);
    }
});

// 5. Check source account balance after transfer
pm.test("Source account balance should be correctly decreased", function() {
    // Only check if transfer is completed
    if (pm.environment.get("transferCompleted")) {
        pm.response.to.have.status(200);
        var jsonData = pm.response.json();

        var previousBalance = parseFloat(pm.environment.get("sourceAccountBalance"));
        var transferAmount = parseFloat(pm.environment.get("transferAmount"));
        var expectedBalance = previousBalance - transferAmount;

        pm.expect(jsonData.balance).to.be.approximately(expectedBalance, 0.001);
    } else {
        pm.test.skip("Transfer not yet completed, skipping balance check");
    }
});

// 6. Check target account balance after transfer
pm.test("Target account balance should be correctly increased", function() {
    // Only check if transfer is completed
    if (pm.environment.get("transferCompleted")) {
        pm.response.to.have.status(200);
        var jsonData = pm.response.json();

        var previousBalance = parseFloat(pm.environment.get("targetAccountBalance"));
        var transferAmount = parseFloat(pm.environment.get("transferAmount"));
        var expectedBalance = previousBalance + transferAmount;

        pm.expect(jsonData.balance).to.be.approximately(expectedBalance, 0.001);
    } else {
        pm.test.skip("Transfer not yet completed, skipping balance check");
    }
});

This example shows how API calls can be tested in a banking scenario. Each step is executed dynamically based on the results of the previous step.

The success of advanced API testing depends on the ability to comprehensively model real-world scenarios. Instead of just testing individual services, you should aim to test the entire system end-to-end to develop more reliable and robust APIs.

0
Subscribe to my newsletter

Read articles from Fatih Mehmet Çiçek directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Fatih Mehmet Çiçek
Fatih Mehmet Çiçek

Experienced QA Engineer with expertise in comprehensive testing methodologies.