In this article, I would like to show you a data-driven approach for REST API testing. If you are new to JMeter/REST API Testing, I would like to read this article first to get some idea.
Goal:
Our aim here is to come up with a framework to test REST API with different HTTP Methods. This test will be driven through a spreadsheet and the spreadsheet will contain all the input parameters, API URL, HTTP Method, request JSON, text response should be used for assertion etc.
By using one single HTTP Sampler, we would like to send different types of request GET / POST / PUT / PATCH / DELETE. Even the HTTP Request body data will be added dynamically at run time.
JSON Server:
I am going to use this JSON-Server for this testing purpose. You can quickly set this up and running within a minute. You could also use your application APIs if you have.
Once it is installed, start the server using below command.
json-server --watch db.json
My db.json looks like this.
{ "books":[ ], "comments":[ ], "profile":{ "name":"typicode" } }
Test Scenarios:
Lets assume, we would like to execute these scenarios as part of our REST API functional testing. Test description provides a high level idea about the test case.
If all requests are actually same and only the data is different as shown below, we could easily do a data-driven testing in JMeter with 1 HTTP Sampler & a CSV DataSet Config.
But in our case, We have 1 GET request, then 5 POST requests, then 1 GET request…etc. We send different types of request. So, we might end up creating our Test Plan as shown here
What will happen if we need to test thousands of scenarios!!? How can we maintain such a huge JMeter test?
Data-Driven Testing:
In order to completely drive the testing through a spreadsheet, Lets move any data which could vary among these HTTP requests to the spreadsheet as shown here after carefully analyzing these requests.
- #1 – A simple GET request to fetch all the items from the books category. For the first test case, we would not have any data. So, it should respond with empty list.
- #2-#6 – We add new books with different titles and authors using POST requests. The input.json for these test cases would be as shown here. We would be replacing the title and author at run time with the corresponding data in the spreadsheet.
{ "title": "${title}", "author": "${author}" }
- #7 & #9 – Simple GET requests for specific book details to check if the POST / PUT requests worked fine.
- #8 – A PUT request to simply replace the current item in the DB with the given data.
{ "title": "${title}", "author": "${author}", "price": "$10.00" }
- #10 – A PATCH request to specifically update a data of the current item in the DB.
{ "title": "${title}" }
- #11 #12 – A DELETE requests to remove an item from the DB.
As we have moved all the variables to the spreadsheet, now by having only one HTTP Sampler in JMeter test and by setting the HTTP Sampler properties/attributes at run time, we could run the entire test.
JMeter Test Plan:
- I add a CSV Data Set Config – to read the test scenarios and input parameters.
- Add a HTTP Sampler and update the details. Let the Method be with some default selection. Also add a Header Manager with Content-Type as application/json
- Add a JSR223 – PreProcessor. This should be responsible for changing the HTTP Method based on the value in the spreadsheet. It also sets the HTTP Request body data for POST / PUT / PATCH requests.
The below statements change the current sampler HTTP Method.
def httpMethod = vars.get("http.method");
sampler.setMethod(httpMethod);
We use below statements to change the HTTP Body. We read the input.json file then we replace the any variable with the corresponding data
def dataToBePosted = new CompoundVariable(new File(vars.get("jmeter.test.home") + vars.get("input.json")).text).execute();
def arg= new HTTPArgument("", dataToBePosted, null, true);
arg.setAlwaysEncoded(false);
sampler.getArguments().addArgument(arg);
- Last step would be to add assertion.
- Run the test plan.
Download:
You can check the JMeter test plan here in GitHub.
Summary:
By moving all the variables to a spreadsheet and with 1 HTTP Sampler, we are able to test different types of requests. Adding any new tests to this test plan is very easy. As you already know, we have to insert one more row in the spreadsheet with the enough information for the new test. By looking at the spreadsheet, you can easily understand our coverage. Any update to the test data would also be easy with this approach instead of updating each and every individual HTTP Requests in JMeter.
Happy Testing & Subscribe 🙂
Thank you yaar. You accepted my request for this post. It will be much easier to functional test and then load test API’s
This is great stuff.
Big fan of yours and your blog
Keep sharing!!!
You are welcome 🙂
unable to open this on Jmeter 3.0 getting com.throughworks.xstream.mapper.cannotresolveclassexception:html
Did you try downloading the sourcecode once again and try opening in latest jmeter 3.1?
Awesome Post.
Thanks 🙂
I’m trying to understand what “jmeter.test.home” is in reference to in the script, as I’m unable to post the body data from the JSON file…I feel this is what is failing my tests.
jmeter.test.home is a variable which gives the absolute path of the current location of the jmx file. Check the test plan element.
Hi I have done the same set up, i downloaded your project zip through git hub in my local system. When i run the jemter i am getting connection error. How can i fix that.
HI,
I am unable to start the JSON server, i downloaded ZIP from git and trying given command but it’s not working. Please do the needful.
Thanks, this article was really helpful.
I have to do some minor changes in the groovy script. I was not using http method variable, I removed.
compound variable is not needed. Also we need to chose encoding, I have used UTF-8.
import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
//set the HTTP request body
if(!vars.get(“input.json”).equals(“”)){
def dataToBePosted = new File(vars.get(“jmeter.test.home”) + vars.get(“input.json”)).text;
//def dataToBePosted = new CompoundVariable(fileContent).execute();
def arg= new HTTPArgument("", dataToBePosted, null, false, "UTF-8");
arg.setAlwaysEncoded(false);
sampler.getArguments().addArgument(arg);
//HTTP Body is set to
log.info(dataToBePosted);
}