API automation #REST-assured
API what is it, why does it matter?
- Application Program Interfaces define the business logic of the application being designed.
- Functional rules - User interaction with services and data.
- Endpoints - Relay information through request-response protocols (typically through a ‘Uniform Resource Identifier’) and gives response.
- SOAP and REST APIs
API Calls interaction |
Why I have to test API ?
Complete coverage! UI testing, either manual or automated, is still just testing the presentation layers to make sure the end user experience matches expectations and meets functional requirements.
If solely using UI testing without data-driven API testing, it’s nearly impossible to validate all different possibilities of how a user could manipulate the application and the related sub-applications. The best approach is to test both UI and API.
Early testing helping shift left.
API testers on a QA team will focus on all the different permutations and scenarios to validate within a single API and among multiple APIs involved in a chain of requests (end-to-end).
Could test APIs without having complete knowledge of the entire system.
Business depend on APIs working 100% as expected hence simpler and more convenient way is to run tests through a series of checks after a build and they’re generally straightforward to create, automate, and maintain.
Quick validation. API automated testing often takes a fraction of the time as UI automated tests.
The bottom line is that API testing offers many advantages to a more traditional manual or automated UI approach. With the right tools and expertise it can supplement existing testing efforts and contribute added capabilities to your testing goals.
How can I test these APIs?
Some Tools....
SoapUI
Postman
Katalon
Studio
Tricentis
Tosca
Apigee
Jmeter
Swagger
Inspector
Assertible
RESTClient
Rest
Assured
Rest
template
HTTP
Restsharp
RestConsole
Chakram
Karate
SuperTest
...♾
Testing a web site REST api - Json using developer tools and Postman
API Automation – REST Assured
Authorization
•CSRF
Headers
Cookies
Sample Code::
public void basicAuthorization() {
REQUEST.auth()
.basic("user1", "user1Pass")
.when()
.get("http://localhost:8080/spring-security-rest-basic-auth/api/foos/1")
.then()
.assertThat()
.statusCode(200)
.getHeader("Date");
public class OAuth2Test {
private String resourceOwnerLogin(String tokenUri, String clientId, String clientSecret, String username, String password, String scope) {
Response response = REQUEST.auth().preemptive().basic(clientId, clientSecret)
.formParam("grant_type", "password")
.formParam("username", username)
.formParam("password", password)
.formParam("scope", scope)
.when()
.post(tokenUri);
String accessToken = response.path("access_token").toString();
String tokenType = response.path("token_type").toString();
String dateHeader = response.getHeader("Expires");
String respCookie = response.getCookie("auth_cookie");
return accessToken;
}
}
Assertions -Json Gpath and Hamcrest Matchers
{
"page": 1,
"per_page":
3,
"total": 12,
"total_pages":
4,
"data":
[
{
"id": 1,
"email": "george.bluth@reqres.in",
"first_name":
"George",
"last_name":
"Bluth",
"avatar":
"https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
},
{
"id": 2,
"email": "janet.weaver@reqres.in",
"first_name":
"Janet",
"last_name":
"Weaver",
"avatar":
"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
},
...
]
}
public RequestSpecification REQUEST;
@Before
public void details() {
RestAssured.baseURI = "https://reqres.in/api";
REQUEST = RestAssured.given().contentType(ContentType.JSON);
}
@Test
public void shouldFetchListOfAllUsers() {
REQUEST
.get("/users")
.then()
.assertThat()
.statusCode(200)
.contentType(ContentType.JSON)
.statusLine(containsString("OK"))
.log().body()
.body("data", hasSize(3))
.body("data[0].id", equalTo(1))
.body("data[0].first_name", equalTo("George"))
.body("data.findAll{it.id>2}.first_name", hasItem("Emma"))
.body("data[0].last_name", not(equalTo("George")));
}
Reference
#
Matchers
Hamcrest
comes with a library of useful matchers. Here are some of the most important
ones.
Core
- anything
- describedAs
- Logical
- allOf
- anyOf
- not
- Object
- equalTo
- hasToString
- instanceOf, isCompatibleType
- notNullValue, nullValue
- sameInstance
- Beans
- hasProperty
- Collections
- array
- hasEntry, hasKey, hasValue
- hasItem, hasItems
- hasItemInArray
- Number
- closeTo
- greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo
- Text
- equalToIgnoringCase
- equalToIgnoringWhiteSpace
- containsString, endsWith, startsWith
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
public class IsNotANumber extends TypeSafeMatcher {
@Override
public boolean matchesSafely(Double number) {
return number.isNaN();
}
public void describeTo(Description description) {
description.appendText("not
a number");
}
public static Matcher notANumber() {
return new
IsNotANumber();
}
}
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static
org.hamcrest.examples.tutorial.IsNotANumber.notANumber;
public class NumberTest {
@Test
public void testSquareRootOfMinusOneIsNotANumber() {
assertThat(Math.sqrt(-1), is(notANumber()));
}
}
Static JSON comparison JsonSchemaValidator
user2.json in
classpath
{
"data":
{
"id": 2,
"email": "janet.weaver@reqres.in",
"first_name":
"Janet",
"last_name":
"Weaver",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
}
}
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import static org.hamcrest.MatcherAssert.assertThat;
@Test
public void shouldGetSecondUserVerifyUsingJsonSchemaValidator() {
String
json = REQUEST.get("/users/2").body().asString();
REQUEST.get("/users/2")
.then()
.statusCode(200)
.time(lessThan(2L), TimeUnit.SECONDS)
.log().all();
assertThat(json, matchesJsonSchemaInClasspath("user2.json"));
}
POJOs
Plain
Old Java Object
not bound by any restriction other than those forced by the Java Language
Specification
SingleUserResponse.java
@JsonPropertyOrder({ "data" })
public class SingleUserResponse {
@JsonProperty("data")
private Data data;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("data")
public Data getData() {
return
data;
}
@JsonProperty("data")
public void setData(Data data) {
this.data = data;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return
this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
} }
Data.java
@JsonPropertyOrder({ "id", "email", "first_name", "last_name", "avatar" })
public class Data {
@JsonProperty("id")
private Integer id;
@JsonProperty("email")
private String email;
@JsonProperty("first_name")
private String firstName;
@JsonProperty("last_name")
private String lastName;
@JsonProperty("avatar")
private String avatar;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("id")
public Integer getId() {
return
id;
}
@JsonProperty("id")
public void setId(Integer id)
{
this.id = id;
}
@JsonProperty("email")
public String getEmail() {
return
email;
}
__
@JsonProperty("email")
public void setEmail(String email) {
this.email = email;
}
@JsonProperty("first_name")
public String getFirstName() {
return
firstName;
}
@JsonProperty("first_name")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@JsonProperty("last_name")
public String getLastName() {
return lastName;
}
@JsonProperty("last_name")
public void setLastName(String lastName) {
this.lastName = lastName;
}
@JsonProperty("avatar")
public String getAvatar() {
return
avatar;
}
@JsonProperty("avatar")
public void setAvatar(String avatar) {
this.avatar = avatar;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return
this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Reference
# http://www.jsonschema2pojo.org/
(De-)Serialize and validate instantly with POJOs
Serializable,
has a no-argument constructor, and allows access to properties
using getter and setter methods
@Test
public void shouldGetFirstUserAndVerifyFirstNameAndId() {
SingleUserResponse usersResponse = REQUEST
.get("/users/1")
.as(SingleUserResponse.class);
Assert.assertEquals(Integer.valueOf(1), usersResponse.getData().getId());
Assert.assertEquals("George", usersResponse.getData().getFirstName());
}
@Test
public void shouldGetSecondUserAndVerifyFirstNameAndId() {
SingleUserResponse usersResponse = REQUEST
.get("/users/2")
.as(SingleUserResponse.class);
Assert.assertEquals(Integer.valueOf(2), usersResponse.getData().getId());
Assert.assertEquals("Janet", usersResponse.getData().getFirstName());
}
POJO and JSON Requests
Request
{
"name": "morpheus",
"job": "zion "
}
POJOs created as
CreateUserRequest.java
Response
{
"name": "morpheus",
"job": "zion ",
"id": "836",
"createdAt":
"2019-07-29T08:56:32.044Z"
}
POJOs created as
UsersResponse.java
@Test
public void createUser() {
HashMap<String,
String> jsonAsMap = new HashMap<String,String>();
jsonAsMap.put("name", "John");
jsonAsMap.put("job", "qa");
REQUEST.contentType(ContentType.JSON)
.body(jsonAsMap)
.post("/users")
.then()
.assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
.statusLine(containsString("Created"))
.log().body();
}
@Test
public void createUserWithPojo() {
CreateUserRequest request = new CreateUserRequest();
request.setName("Jane");
request.setJob("UX");
UsersResponse usersResponse = REQUEST.contentType(ContentType.JSON)
.body(request)
.post("/users")
.as(UsersResponse.class);
id = usersResponse.id;
System.out.println(usersResponse.id);
}