Introduction
In our previous post, we explored Mocking APIs using REST Assured and WireMock, learning how to simulate API behavior. Now, we’ll dive into Performance Testing, a technique to evaluate an API’s speed, scalability, and stability under load. This guide combines REST Assured with simple multi-threading and introduces Apache JMeter for comprehensive performance testing. It’s designed for beginners and experienced developers, providing clear explanations and practical examples.
Key Point: Performance testing with REST Assured helps measure API response times and behavior under load, ensuring it meets performance requirements.
What is Performance Testing?
Performance Testing assesses an API’s performance characteristics, such as:
- Response Time: How quickly the API responds to a request.
- Throughput: Number of requests processed per second.
- Scalability: Ability to handle increased load.
- Stability: Reliability under sustained load.
REST Assured is primarily a functional testing tool, but it can be used for basic performance testing by measuring response times or running multiple requests concurrently. For advanced load testing, tools like Apache JMeter or Gatling are recommended, and we’ll show how to complement REST Assured with JMeter.
Setting Up for Performance Testing
To perform performance testing, we’ll use:
- REST Assured for basic response time measurement and concurrent requests.
- Apache JMeter for advanced load testing, integrated with REST Assured concepts.
- The public API
https://jsonplaceholder.typicode.com
for testing.
Ensure your pom.xml
includes dependencies for REST Assured and JUnit:
io.rest-assured
rest-assured
5.4.0
test
org.junit.jupiter
junit-jupiter
5.10.2
test
org.hamcrest
hamcrest
2.2
test
No additional dependencies are needed for basic performance testing with REST Assured. For JMeter, download it from the official site and install it separately.
Performance Testing with REST Assured
Let’s explore how to measure API performance using REST Assured, focusing on response time and concurrent requests.
Example 1: Measuring Response Time
Use REST Assured to measure the time taken for an API request.
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
public class ResponseTimeTest {
@Test
public void testResponseTime() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.extract().response();
long responseTime = response.getTime(); // Time in milliseconds
System.out.println("Response Time: " + responseTime + " ms");
assertTrue(responseTime < 2000, "Response time should be less than 2 seconds");
}
}
Explanation:
response.getTime()
: Returns the response time in milliseconds.assertTrue(responseTime < 2000)
: Ensures the response time is under 2 seconds.- This test measures the performance of a single request.
Important: Response times can vary due to network conditions. Run tests multiple times and calculate averages for reliable results.
Example 2: Simulating Load with Concurrent Requests
Use Java’s ExecutorService
to send multiple concurrent requests and measure performance.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
public class ConcurrentRequestsTest {
@Test
public void testConcurrentRequests() throws InterruptedException {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
int numberOfRequests = 10;
List responseTimes = new ArrayList<>();
ExecutorService executor = Executors.newFixedThreadPool(numberOfRequests);
long startTime = System.currentTimeMillis();
for (int i = 0; i < numberOfRequests; i++) {
executor.submit(() -> {
long time = given()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.extract().response().getTime();
synchronized (responseTimes) {
responseTimes.add(time);
}
});
}
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
long endTime = System.currentTimeMillis();
long totalDuration = endTime - startTime;
double averageResponseTime = responseTimes.stream().mapToLong(Long::longValue).average().orElse(0);
System.out.println("Total Duration: " + totalDuration + " ms");
System.out.println("Average Response Time: " + averageResponseTime + " ms");
assertTrue(averageResponseTime < 2000, "Average response time should be less than 2 seconds");
}
}
Explanation:
ExecutorService
: Creates a thread pool to send 10 concurrent GET requests.responseTimes
: Collects response times for each request.averageResponseTime
: Calculates the average response time.- The test measures how the API handles concurrent load.
Pro Tip: For basic load testing, limit the number of concurrent requests to avoid overwhelming the API or your local machine. Use dedicated tools like JMeter for high-load scenarios.
Using Apache JMeter for Advanced Performance Testing
While REST Assured is great for functional and basic performance testing, Apache JMeter excels at load and stress testing. You can use REST Assured to validate functional behavior and JMeter to simulate heavy load.
Example: Creating a JMeter Test Plan for an API
Steps to create a JMeter test plan for the https://jsonplaceholder.typicode.com/posts
endpoint:
- Download and Install JMeter: Get JMeter from here and extract it.
- Create a Test Plan:
- Open JMeter and add a Thread Group (Right-click Test Plan > Add > Threads > Thread Group).
- Set Number of Threads (e.g., 50), Ramp-Up Period (e.g., 10 seconds), and Loop Count (e.g., 1).
- Add HTTP Request:
- Right-click Thread Group > Add > Sampler > HTTP Request.
- Set Server Name:
jsonplaceholder.typicode.com
, Path:/posts
, Method: GET.
- Add Listeners:
- Add Summary Report and View Results Tree (Right-click Thread Group > Add > Listener).
- Run the Test: Click the green play button and review results in the listeners.
Sample JMeter Configuration (XML for Reference):
50
10
1
jsonplaceholder.typicode.com
/posts
GET
Explanation:
- Thread Group: Simulates 50 users making requests over 10 seconds.
- HTTP Request: Sends GET requests to
/posts
. - Listeners: Display performance metrics like average response time and throughput.
Use REST Assured to validate the functional correctness of the API (e.g., response body) before running JMeter for load testing.
Step 1: Combining REST Assured with JMeter
Use REST Assured to ensure the API’s functional behavior and JMeter to test performance.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class FunctionalValidationTest {
@Test
public void testFunctionalValidationBeforeLoad() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.when()
.get("/posts")
.then()
.statusCode(200)
.body("[0].id", equalTo(1))
.body("[0].title", notNullValue());
}
}
Explanation:
- Run this REST Assured test to confirm the API returns correct data.
- Then use the JMeter test plan above to simulate load and measure performance.
Step 2: Measuring Response Time with Request Specification
Use a Request Specification in REST Assured for consistent performance tests.
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
public class PerformanceSpecTest {
private static RequestSpecification requestSpec;
@BeforeAll
public static void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://jsonplaceholder.typicode.com")
.addHeader("Accept", "application/json")
.build();
}
@Test
public void testResponseTimeWithSpec() {
Response response = given()
.spec(requestSpec)
.when()
.get("/posts/1")
.then()
.statusCode(200)
.extract().response();
long responseTime = response.getTime();
System.out.println("Response Time: " + responseTime + " ms");
assertTrue(responseTime < 2000, "Response time should be less than 2 seconds");
}
}
Explanation:
requestSpec
: Defines the base URI and headers.spec(requestSpec)
: Applies the specification for consistent testing.- Measures response time for a single request.
Step 3: Verify Setup with pom.xml
Ensure your pom.xml
includes all required dependencies:
io.rest-assured
rest-assured
5.4.0
test
org.junit.jupiter
junit-jupiter
5.10.2
test
org.hamcrest
hamcrest
2.2
test
Run the tests using mvn test
or your IDE’s test runner. For JMeter, run the test plan via the JMeter GUI or command line.
Tips for Beginners
- Use REST Assured for Functional Testing: Validate API behavior before performance testing.
- Start with Low Load: Test with a small number of threads in JMeter or concurrent requests in REST Assured to avoid overwhelming the API.
- Monitor Metrics: Focus on response time, throughput, and error rates in JMeter reports.
- Enable Logging: Use
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails()
to debug performance issues.
Troubleshooting Tip: If performance tests show high response times, check network latency, API rate limits, or server capacity. Use JMeter listeners to identify bottlenecks.
What’s Next?
In the next post, we’ll cover Logging and Debugging, exploring how to log requests and responses in REST Assured for effective troubleshooting. Stay tuned for more hands-on examples!