How to get started with Rest Assured for API tests
I’m aware there are already plenty of Rest Assured tutorials available on the internet. This is a good thing, as it shows that Rest Assured has truly made its way to become one of the most known and used testing frameworks out there. Within this tutorial, I’ll try to show you how I use Rest Assured for Java backend tests here within HMH. I hope you will find it useful.
Shall we get started then? :)
We’ll do this in the context of a Maven project, so the first thing we need to do is to add the Rest Assured dependencies to our pom file.
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
But just a bit before getting into the code, let’s see the API we’ll be automating: We’ll start with an api that retrieves a SIF (JWT) token for a login after receiving some valid username and password. This is it here when manually tested through Postman:
Here we can see our api uses the POST http method. It then sends a body with some parameters and we expect to receive a 200 success status code as part of the response as well as Json body with the SIF information we are looking for. We can then later use this token as a header to authenticate our user through other apis.
There are a couple of ways to start with that but one I normally use and would encourage you to is creating models for the class that represents our request body. So for this case, the body we are sending:
{
”username”:”someUsername”
“password”:”aPassword!”,
}
As a model class would become something like:
class MyClass {
String username;
String password;
}// getters and setters
A nice tip in order to simplify our class and avoid manually creating constructors, getters and setters is to annotate it with the Lombok annotations. Like this:
@Data // @Getter and @Setter already inside this annotation
@AllArgsConstructor
@NoArgsConstructor
class MyClass {
String username;
String password;
}
Then now we can create a helper with the Rest Assured setup.
public static RequestSpecification getRequestSpecification() {
return given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.when()
.log()
.everything();
}
Here we are saying we want our requests to accept and return JSON as the content type and for them to be logged when the tests run so it’s easier for us to follow through what is happening along their execution.
Once we have this helper method, we can call it like this:
RequestSpecification rq = getRequestSpecification();
Response r = rq.body(map).post(url);
And here we would have the response for our API call which we can assert within our tests as in:
@Test
void myTest() { String url = "http://my.api.com/login";
String username = "someUsername";
String password = "aPassword";
Map<String, Object> map = new HashMap<>();
map.put("username", username);
map.put("password", password);
RequestSpecification rq = getRequestSpecification();
Response response = rq.body(map).post(url); assertEquals(200, response.statusCode());
assertNotNull(response.getBody().jsonPath().get("sifToken"));
}
And here we’re actually done. Congratulations! You just automated your first Rest Assured test! :)
But I’m sure you’re telling me: “hey, hey, we haven’t used our model class yet!” Yes, you’re correct. We added the body for the request payload using a map instead. Remember I mentioned there are a few ways to do this? Yes, Rest Assured is flexible enough to accept different object types. Normally for small bodies, sometimes it can be okay to do it as we just did it here, but I’d again strongly suggest you go with the model pattern instead. It will scale much better, especially when you have longer bodies for the request or response.
So here is the same method using our model class:
@Test
void myTest() {
String url = "http://my.api.com/login";
String username = "someUsername";
String password = "aPassword"; MyClass myClass = new MyClass(username, password);
RequestSpecification rq = getRequestSpecification();
Response response = rq.body(myClass).post(url); assertEquals(200, response.statusCode());
assertNotNull(response.getBody().jsonPath().get("sifToken"));
}
It’s worth it noting that sometimes we may need to serialise/deserialise some of our classes. There are a few nice frameworks out there that can help you with this. If you’re using Spring you probably already have Jackson pre-bundled on your project, so you may be better sticking to it. Otherwise, if you don’t have Spring, you can add Jackson as a separate dependency. If you’d prefer to use something such as Gson instead, this should also be fine, but it may require some extra configuration as Rest Assured also uses Jackson as its default serialiser/deserialiser. If you keep reading, you’ll find an example where we use Jackson here.
Also, whenever creating your model class it may be easier to use a tool that does this for you. JsonSchema2Pojo is one of the most popular tools out there and one we also use. You just need to copy your json body there and it will give you back your model (Pojo) class.
Okay, that’s great, but if you still have the appetite for a bit more, we can try and use the token we just got to authenticate the user into our next API call.
To do this let’s copy what we have inside our test and turn it into a helper method:
private String getAuthorizationToken() {
String url = "http://my.api.com/login";
String username = "someUsername";
String password = "aPassword";MyClass myClass = new MyClass(username, password);
RequestSpecification rq = getRequestSpecification();
Response response = rq.body(myClass).post(url);assertEquals(200, response.statusCode());
assertNotNull(response.getBody().jsonPath().get("sifToken"));
}
And here is the GET endpoint we’ll be automating:
As a get request, it does not require a model class for body params since it doesn’t have any. However, it would be nice to add it to our response, so it can be easier to do the assertions on what we’re getting there.
package com.example;
import java.util.List;@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyClass { private Integer totalMeetings;
private Integer totalPages;
private Integer pageSize;
private Integer pageNumber;
private List<Object> meetings = null;
}
Please note we’re using a sample here where the meetings object respond with an empty list. This is to simplify this tutorial, but if we’re also verifying and asserting for the meetings object as well, that would require its own model class when generated through the json2schema tool.
Now back to our tests we can do the following:
@Test
void myTest() { String url = "http://my.api.com/meeting";
String authorizationCode = getAuthorizationCode(); RequestSpecification rq = getRequestSpecification()
.header(authorizationCode);
Response response = rq.get(getUrl); assertEquals(200, response.statusCode()); assertEquals(0, response.getBody().jsonPath().get("totalMeetings")); assertEquals(0, response.getBody().jsonPath().get("totalPages")); assertEquals(20, response.getBody().jsonPath().get("pageSize")); assertEquals(0, response.getBody().jsonPath().get("pageNumber")); assertNull(0, response.getBody().jsonPath().get("meetings"));}
Here again we are showing the case where we’re not using our model class. But if we want to change that (and we probably do), the same method would be turned into:
@Test
void myTest() { String url = "http://my.api.com/meeting";
String authorizationCode = getAuthorizationCode(); RequestSpecification rq = getRequestSpecification()
.header(authorizationCode);
Response response = rq.get(getUrl); ObjectMapper mapper = new ObjectMapper();
Meeting meeting = mapper.convertValue(response.getBody().jsonPath().get(), Meeting.class) assertEquals(200, response.statusCode());
assertEquals(0, meeting.getTotalMeetings());
assertEquals(0, meeting.getTotalPages());
assertEquals(20, meeting.getPageSize());
assertEquals(0, meeting.getPageNumber());
assertNull(0, meeting.get("meetings"));
}
This is also a good example for where we would use Jackson to deserialise our response and turn into a Pojo.
So I guess this is really it now. Thank you for reading and have a good one!