Testing a REST API

Testing tasks are fundamental on the software development process. These tasks goals are covering the different quality axes of each of the diverse artifacts developed. Unit testing, Load Testing, Integration testing are just some examples of the many types of possible test types. Each one has a different purpose, for instance unit testing allows us to ensure the code provides the expected result. Integration testing on the other hand allows to review that combining different units or components will provide the expected results.

For the purpose of this post we are doing test that allow us to ensure the REST services developed on Developing a CRUD REST API on IBM Bluemix are up, running correctly. Please be aware that the test are not to review the results are valid or not, just to review they are running and what is the time they take to respond.

On this post we will show you three (3) different approaches that allow us to repeat the test several times to provide appropriate response times. These test are the base of our load testing tasks we will use on or next series of posts.

The first approach we will be using the cURL command. These commands with the appropriate Bash script programming will allow you to automatize the test. The second approach is to use Java JAX-RS client, in our case we are using the RESTEasy http://resteasy.jboss.org implementation from Jboss, the approach can be used for Junit testing, as we show you. The last approach is a Python approach using the Requests Library.

Of the three approach we prefer either the Java or Python approach, we are sure there are several others for the languages you may choose.

cURL

This approach would be useful if you are running a UN*X OS, since in general you don’t need to install anything on your console.

– You need to review the path and Http method you are using in your code and set it with the -X flag, also the appropriate url.
– The header is set with the -H flag
– The Json object must be correctly written, preferably with a text editor to verify the syntax. Use the -d flag to pass the data to the rest service

Thats it, quickly you have review the server is running and responding

NOTE:Please review the url you are using for this.

curl -X POST -H "Content-Type: application/json" -d '{"lastname":"Smith","name":"Jhon","country":"Colombia","city":"Cartagena"}' http://at3people.mybluemix.net/api/people
curl -X GET -H "Content-Type: application/json" http://at3people.mybluemix.net/api/people
curl -X PUT -H "Content-Type: application/json" -d '{"id":"2","lastname":"Smith","name":"Jhon","country":"Colombia","city":"Cartagena"}' http://at3people.mybluemix.net/api/people
curl -X DELETE "Content-Type: application/json" http://at3people.mybluemix.net/api/people/2
curl -X GET -H "Content-Type: application/json" http://at3people.mybluemix.net/api/people/find/2

JAX-RS Client

This approach won’t be as fast as the cURL approach but allow you to quickly modify and new Data without the Json syntax burden
– Create a new Maven project without selecting any archetype
– Setup your Maven dependencies with the following RestEasy libraries

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>3.0.8.Final</version>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jackson-provider</artifactId>
    <version>3.0.8.Final</version>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxrs</artifactId>
    <version>3.0.8.Final</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>

– You must create or copy the POJO you create in your REST project to keep the same structure
– Now implement the code as follows
public class TestPeopleService {

	private final String URL = "http://at3people.mybluemix.net/api/people";

	private Client client;

	@Before
	public void setup() {
		client = ClientBuilder.newClient();
	}

	@Test
	public void create() {

		WebTarget target = client.target(URL);

		Person p = new Person("Smith", "Jhon", "Colombia", "Cartagena");
		Response response = target.request().post(
				Entity.entity(p, MediaType.APPLICATION_JSON));

		if (response.getStatus() != 200) {
			fail("RESPONSE STATUS" + response.getStatus());
		}
	}

	@Test
	public void find() {
		String id = "55";
		WebTarget target = client.target(URL + "/find/" + id);
		Response response = target.request().get();
		if (response.getStatus() != 200) {
			fail("RESPONSE STATUS" + response.getStatus());
		}

	}

	@Test
	public void list() {
		WebTarget target = client.target(URL);
		Response response = target.request().get();
		if (response.getStatus() != 200) {
			fail("RESPONSE STATUS" + response.getStatus());
		}

	}

	@Test
	public void update() {
		WebTarget target = client.target(URL);

		Person p = new Person("Smith", "Jhon", "Colombia", "Cartagena");
		p.setId(56);
		Response response = target.request().put(
				Entity.entity(p, MediaType.APPLICATION_JSON));
		if (response.getStatus() != 204) {
			fail("RESPONSE STATUS" + response.getStatus());
		}
	}

	@Test
	public void delete() {
		String id = "51";
		WebTarget target = client.target(URL+"/"+id);
		Response response = target.request().delete();
		if (response.getStatus() != 204) {
			fail("RESPONSE STATUS" + response.getStatus());
		}
	}
}

– Thats it now you can run your test again and again, modify the data quickly and without knowledge of the Json syntax

Python and Requests Client

– On our final approach you must install a python library call Requests, you can quickly using the command pip install requests, this is the most recomendable way to installed.
– If you are using ports you can install the pip command using this command sudo port install py34-pip
– Now that you have the libraries ready you can use the following code for your test

import unittest
import requests
import json


class Test(unittest.TestCase):

    url = 'http://at3people.mybluemix.net/api/people'

    def testList(self):
        r = requests.get(Test.url)
        if r.status_code == 200:
            pass
        else:
            self.fail(r.status_code)
    def testFind(self):
        r = requests.get(Test.url+'/find/53')
        if r.status_code == 200:
            pass
        else:
            self.fail(r.status_code)
    def testCreate(self):
        headers = {'content-type':'application/json'}
        payload = {'lastname':'Doe','name':'Jane','country':'Colombia','city':'Medellin'}
        r = requests.post(Test.url,data=json.dumps(payload),headers=headers)
        if r.status_code == 200:
            pass
        else:
            self.fail(r.status_code)
    def testUpdate(self):
        headers = {'content-type':'application/json'}
        payload = {'id':'51','lastname':'Doe','name':'Jane','country':'Colombia','city':'Medellin'}
        r = requests.put(Test.url,data=json.dumps(payload),headers=headers)
        if r.status_code == 204:
            pass
        else:
            self.fail(r.status_code)
    def testDelete(self):
        r = requests.delete(Test.url+'/54')
        if r.status_code == 204:
            pass
        else:
            self.fail(r.status_code)
            
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

Run it a compare.

We use all the above approaches, which one to choose depends on your background and requirements, if you just want to review the results of your REST services there are several plugins for Firefox that will allow you to quickly test them. However our purpose is to do some load testing so the python approach is the one works better for us. The java approach should help you create better unit testing, however we encourage you to write complete test that have no dependencies on each test or the data that is already into the system.

Please visit us at to keep up to date into our post https://www.facebook.com/advtek or our twitter @AdvTeknology

Leave a Reply