Jmeter : Rest API load testing using Apache Jmeter

Hello everyone, welcome to our session. Today we will learn how to load test a JSON Rest API using JMeter.

As a QA engineer, you probably incorporate many types of tests into your code checking: unit tests, integration tests, UI tests, functional tests, security tests, and more. Infrequently, load tests might be overlooked in a sprint or release process. After all, if the system is working under functional testing, it’s good to go, right? Wrong.


Why load testing is important?

This testing customarily identifies - 
  • The maximum operating capacity of an application 
  • Determine whether the current infrastructure is adequate to run the application 
  • Sustainability of application with veneration to peak utilizer load 
  • Number of concurrent users that an application can fortify and scalability to sanction more users to access it.
Some astronomically popular sites have suffered solemn downtimes when they get massive traffic volumes. E-commerce websites invest heavily in advertising campaigns, but not in Load Testing to ascertain optimal system performance when that marketing brings in traffic.

How to load test a JSON Rest API using Jmeter?

First, download and install Jmeter

Click on the ‘Apache-JMeter-5.0.zip’ link to download the binary zip file of JMeter.


By default, the file will be downloaded in the Downloads folder. Open the folder, right-click on the zip file and click on Extract Here from the pop-up menu.

Run Jmeter

How to install Apache JMeter in Ubuntu?
Go to the location from where you can run JMeter.  Downloads/apache-jmeter-5.0/bin/ 
Run the following command to run JMeter and open the JMeter dialog box.
$ ./jmeter

How to install Apache JMeter in Windows?
to run JMeter: 
Browse to bin/ folder by double-clicking on it, 
double-click on jmeter.bat to run it,
It should open both a command-line terminal and JMeter’s UI.

The following dialog box will appear after the successful installation of JMeter.


How to load test a JSON Rest API using Jmeter?

We developed a REST API using Spring Boot for our demo purpose. We are going to load test a POST request "localhost:8080/user"

Step 1. Add a Thread Group 

Right Click ->  Add- > Thread Group
Here we defined “Number of Threads = 500”, Ramp-up period, and “Loop Count = 1”. I named the Thread Group “Simple load test demo”.


Step 2. Add an HTTP Request.

 Right Click on REST Example -> Add -> Sampler -> HTTP Request.



Fill in the obligatory values: 
  • Name - the denomination of the current sampler 
  • Protocol - by default this is HTTP, but it can withal be HTTPS or FILE 
  • Server - the IP address or domain name of the server. This field is required 
  • Port - the web server the port listens to. By default: 80 
  • Method - GET, POST, PUT, DELETE, etc. This field is required 
  • Path - The path to the resource. If this requires string parameters in the query, integrate them below in the “Send Parameters With the Request” section 
  • Content encoding - if you are utilizing POST, PUT, PATCH, or FILE, there is a character encoding to be used
In our case, the request is POST.

Step 3. Set a Content-Type header 

Right click on Test Plan -> Add -> Config element -> HTTP Header Manager
Add a “Content-Type” field equal to “application/json”, as shown in the picture below:



Step 4. Add a Listener to see the Request response.

Right Click on REST Example -> Add -> Listener -> View Results Tree 
It will look like this:



And 

Right Click on REST Example -> Add -> Listener -> Aggregate Report
It will look like this:


Now, you can click on the start button to start the test based on the assigned configurations.

View Results Tree


Aggregate Report



See here we tested 500 samples, Error percentage is 51.80%. Means 255 request fails.

Below is our Spring Boot code to build REST  API. While call a POST request to the endpoint '/user' back-end side will generate a random string and preserve that String to H2 in-memory Database. Functionality wise it is working. But there is a chance to regenerate the same random string. Utilizing the  Load test I identified the back-end application load test failed because the same random string engendered.

Spring Boot Rest Controller

This HomeController.java class will export REST API "/user".

package com.knf.dev.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.knf.dev.Entity.User;
import com.knf.dev.reposiory.UserRepository;

@RestController
public class HomeController {
@Autowired
UserRepository repository;

@PostMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> listAllUsers() {
String id = null;
User user = new User();
try {
// Generate random String of given size in Java
String alphaNumericString = "0123456789";
// create StringBuffer size of AlphaNumericString
StringBuilder sb = new StringBuilder(6);
for (int i = 0; i < 3; i++) {

// generate a random number between
// 0 to AlphaNumericString variable length
int index = (int) (alphaNumericString.length() *
Math.random());

// add Character one by one in end of sb
sb.append(alphaNumericString.charAt(index));
}
id = sb.toString();
List<User> userLIst = new ArrayList<>();
userLIst = (List<User>) repository.findAll();
for (User u : userLIst) {

if (u.getId().equalsIgnoreCase(id))

{
User userObj = new User();
userObj.setError("server error");
return new ResponseEntity<User>(userObj,
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
user.setId(id);
repository.save(user);

} catch (Exception e) {
User userObj = new User();
userObj.setError("server error");
return new ResponseEntity<User>(userObj,
HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
}

Here we are using H2-In-memory Database to save the data.

User.java

package com.knf.dev.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User {
@Id
@Column(unique = true)
private String id;
private String error;
public String getId() {
return id;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public void setId(String id) {
this.id = id;
}
}

UserRepository.java

package com.knf.dev.reposiory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.knf.dev.entity.User;

@Repository
public interface UserRepository extends CrudRepository<User, String> {

}

MainApplication.java

package com.knf.dev;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}

}

Maven[pom.xml]

<?xml version="1.0" encoding="UTF-8"?>
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot_restAPIS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_restAPIS</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Run 
$ mvn spring-boot:run

We have only one REST Service endpoint, ie localhost:8080/user[POST]. 

Here we used the Spring Boot Framework to build REST API. You have n number of Frameworks to build REST Service.


Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete