Skip to content

Instantly share code, notes, and snippets.

@rppowell-lasfs
Last active December 1, 2018 23:45
Show Gist options
  • Save rppowell-lasfs/522b2698825f362a83cf4af992c18800 to your computer and use it in GitHub Desktop.
Save rppowell-lasfs/522b2698825f362a83cf4af992c18800 to your computer and use it in GitHub Desktop.
API Testing Examples using TestNG, RESTAssured, JSONPath, JSONAssert
/* build.gradle
dependencies {
// https://mvnrepository.com/artifact/org.testng/testng
testCompile group: 'org.testng', name: 'testng', version: '6.14.3'
// https://mvnrepository.com/artifact/io.rest-assured/rest-assured
testCompile group: 'io.rest-assured', name: 'rest-assured', version: '3.1.0'
// https://mvnrepository.com/artifact/io.rest-assured/json-schema-validator
testCompile group: 'io.rest-assured', name: 'json-schema-validator', version: '3.1.0'
// https://mvnrepository.com/artifact/org.hamcrest/java-hamcrest
testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0'
// https://mvnrepository.com/artifact/uk.co.datumedge/hamcrest-json
testCompile group: 'uk.co.datumedge', name: 'hamcrest-json', version: '0.2'
// https://mvnrepository.com/artifact/org.skyscreamer/jsonassert
testCompile group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.0'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
testCompile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
// https://mvnrepository.com/artifact/org.glassfish/javax.json
testCompile group: 'org.glassfish', name: 'javax.json', version: '1.1.3'
<!-- https://mvnrepository.com/artifact/org.glassfish/javax.json -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
testCompile group: 'junit', name: 'junit', version: '4.12'
}
*/
/* API json
{"datetime": "2018-07-14 16:17:31.577797", "data": [{"id": "id-one", "foo": "bar"}, {"id": "id-two", "bash": {"one": "test string", "two": 123, "three": [1, 2, 3]}}, {"id": "id-three", "data-strings": ["foo", "bar", "bash"]}]}
*/
/* APITestExampleMockService.py
#!/usr/bin/python3
"""
Very simple HTTP server in python
Usage::
./mockserver003.py [<port>]
Get a GET request::
curl http://localhost
"""
import socket
from http.server import BaseHTTPRequestHandler, HTTPServer
import time, datetime, json
class S(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
j = {
'datetime': str(datetime.datetime.now()),
'data' :[
{ 'id': 'id-one', 'foo': 'bar'},
{ 'id': 'id-two', 'bash':
{'one': 'test string', 'two': 123, 'three': [1, 2, 3]}
},
{ 'id': 'id-three', 'data-strings': ['foo', 'bar', 'bash'] }
]
}
self.wfile.write(bytes(json.dumps(j), 'utf-8'))
def run(server_class=HTTPServer, handler_class=S, hostname='', hostport=8081):
httpd = server_class((hostname, hostport), S)
print(time.asctime(), "Starting server - %s:%s" %(hostname, hostport))
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
print(time.asctime(), "Server stops - %s:%s" %(hostname, hostport))
if __name__ == '__main__':
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
*/
/*
References
https://github.com/rest-assured/rest-assured/wiki/GettingStarted
https://github.com/rest-assured/rest-assured/blob/master/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/GivenWhenThenExtractITest.java
https://github.com/rest-assured/rest-assured/wiki/GettingStarted#json-schema-validation
*/
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import io.restassured.path.json.JsonPath;
import org.json.JSONArray;
import org.json.JSONException;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONParser;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import javax.json.Json;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchema;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.collection.IsIterableContainingInRelativeOrder.containsInRelativeOrder;
import static org.hamcrest.text.MatchesPattern.matchesPattern;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
public class APITestExample {
HttpServer server;
@BeforeClass
public void setup() throws IOException {
System.out.println("Setup()");
server = HttpServer.create(new InetSocketAddress(8081), 0);
server.createContext("/mockservice", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
@AfterClass
public void teardown() {
System.out.println("Teardown()");
server.stop(0);
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
String response;
String json = Json.createObjectBuilder()
.add("datetime", ZonedDateTime.now( ZoneOffset.UTC ).format( DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS") ))
.add( "data", Json.createArrayBuilder()
.add(Json.createObjectBuilder().add("id", "id-one").add("foo", "bar").build())
.add(Json.createObjectBuilder().add("id", "id-two").add("bash",
Json.createObjectBuilder()
.add("one", "test string")
.add("two", 123)
.add("three", Json.createArrayBuilder().add(1).add(2).add(3))
)
)
.add(Json.createObjectBuilder().add("id", "id-three").add("data-strings", Json.createArrayBuilder().add("foo").add("bar").add("bash")))
)
.build()
.toString();
System.out.println(json);
//response = "This is the response";
String dummy="{\"datetime\": \"2018-07-14 16:17:31.577797\", \"data\": [{\"id\": \"id-one\", \"foo\": \"bar\"}, {\"id\": \"id-two\", \"bash\": {\"one\": \"test string\", \"two\": 123, \"three\": [1, 2, 3]}}, {\"id\": \"id-three\", \"data-strings\": [\"foo\", \"bar\", \"bash\"]}]}";
System.out.println(dummy);
response=json;
t.getResponseHeaders().set("Content-Type", "application/json");
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
@Test
public void doAPITestExample() throws JSONException, IOException {
Response response = RestAssured.given()
.log().all()
.get("http://localhost:8081/mockservice");
response.then()
.log().all()
.assertThat().statusCode(200);
String body = response.getBody().asString();
System.out.println("Body:" + body);
System.out.println("data property:" + response.then().extract().path("data").toString());
/*
{"datetime": "2018-07-14 16:19:18.829697", "data": [{"id": "id-one", "foo": "bar"}, {"id": "id-two", "bash": {"one": "test string", "two": 123, "three": [1, 2, 3]}}, {"id": "id-three", "data-strings": ["foo", "bar", "bash"]}]}
*/
// RESTAssured verifing JSON
// https://github.com/rest-assured/rest-assured/wiki/Usage#example-1---json
// https://github.com/rest-assured/rest-assured/wiki/Usage#json-example
String datetimePatternString = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{6}$";
Pattern datetimePattern = Pattern.compile(datetimePatternString);
response.then().body("datetime", matchesPattern(datetimePattern));
response.then().body("data.size()", is(3));
response.then().body("data[0].size()", is(2));
response.then().body("data[0].id", is("id-one"));
response.then().body("data[0].foo", is("bar"));
response.then().body("data[1].size()", is(2));
response.then().body("data[1].id", is("id-two"));
response.then().body("data[1].bash", isA(HashMap.class));
response.then().body("data[1].bash.one", isA(String.class));
response.then().body("data[1].bash.one", equalTo("test string"));
response.then().body("data[1].bash.two", isA(Integer.class));
response.then().body("data[1].bash.two", equalTo(123));
response.then().body("data[1].bash.three", isA(ArrayList.class)) ;
response.then().body("data[1].bash.three.size()", is(3));
response.then().body("data[1].bash.three", hasItems(1, 2, 3));
response.then().body("data[2].size()", is(2));
response.then().body("data[2].id", is("id-three"));
response.then().body("data[2].data-strings", isA(ArrayList.class)) ;
response.then().body("data[2].data-strings.size()", is(3));
response.then().body("data[2].data-strings", hasItems("foo", "bar", "bash"));
response.then().body("data[2].data-strings", hasItems("bash", "bar", "bar"));
response.then().body("data[2].data-strings", containsInAnyOrder("foo", "bar", "bash"));
response.then().body("data[2].data-strings", containsInAnyOrder("bash", "bar", "foo"));
response.then().body("data[2].data-strings", containsInRelativeOrder("foo", "bar", "bash"));
// data[0] entry
response.then().root("data[0]")
.body("size()", is(2))
.body("id", is("id-one"))
.body("foo", is("bar"));
// data[1] entry
response.then().root("data[1]")
.body("size()", is(2))
.body("id", is("id-two"))
.body("bash", isA(HashMap.class))
.body("bash.one", isA(String.class))
.body("bash.one", equalTo("test string"))
.body("bash.two", isA(Integer.class))
.body("bash.two", equalTo(123))
.body("bash.three", isA(ArrayList.class))
.body("bash.three.size()", is(3))
.body("bash.three.", hasItems(1, 2, 3));
// data[2] entry
response.then().root("data[2]")
.body("size()", is(2))
.body("id", is("id-three"))
.body("data-strings", isA(ArrayList.class))
.body("data-strings", containsInRelativeOrder("foo", "bar", "bash"));
// extract id from data[] and verify expected values
response.then().body("data.id", hasItems("id-one", "id-two", "id-three"));
response.then().body("data.id", hasItems("id-three", "id-two", "id-one"));
response.then().body("data.id", containsInAnyOrder("id-one", "id-two", "id-three"));
response.then().body("data.id", containsInAnyOrder("id-three", "id-two", "id-one"));
response.then().body("data.id", containsInRelativeOrder("id-one", "id-two", "id-three"));
// https://github.com/hertzsprung/hamcrest-json
//response.then().body("data.id", sameJSONAs("[\"id-one\", \"id-two\", \"id-three\"]").allowingAnyArrayOrdering());
// Asserting against expected ArrayList<String>
ArrayList<String> data_id_array = response.then().extract().path("data.id");
Assert.assertEquals(new ArrayList(Arrays.asList("id-one", "id-two", "id-three")), data_id_array);
// Hamcrest Matchers
assertThat(data_id_array, containsInRelativeOrder("id-one", "id-two", "id-three") );
// able to compare entire body with JSONAssert, strict=false to ignore datetime
// http://jsonassert.skyscreamer.org/
String expectedJSON = "{\"data\": [{\"id\": \"id-one\", \"foo\": \"bar\"}, {\"id\": \"id-two\", \"bash\": {\"one\": \"test string\", \"two\": 123, \"three\": [1, 2, 3]}}, {\"id\": \"id-three\", \"data-strings\": [\"foo\", \"bar\", \"bash\"]}]}";
JSONAssert.assertEquals(expectedJSON, response.getBody().asString(), false);
// extract and convert data entry to String using Gson
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
String dataJSONArrayString = gson.toJson((ArrayList)response.then().extract().path("data"));
// using JsonPath from String
List<Map<String, ?>> dataEntries = JsonPath.from(dataJSONArrayString).get();
Assert.assertEquals(dataEntries.size(),3, "data entry count");
Assert.assertEquals(dataEntries.get(0).get("id"), "id-one", "id-one matches");
Assert.assertEquals(dataEntries.get(1).get("id"),"id-two", "id-two matches");
Assert.assertEquals(dataEntries.get(2).get("id"),"id-three", "id-three matches");
// using JSONAssert to compare JSONArray from String
JSONArray dataJSONArray = (JSONArray) JSONParser.parseJSON(dataJSONArrayString);
String expectedDataJSONArrayAsString = "[{\"id\": \"id-one\", \"foo\": \"bar\"}, {\"id\": \"id-two\", \"bash\": {\"one\": \"test string\", \"two\": 123, \"three\": [1, 2, 3]}}, {\"id\": \"id-three\", \"data-strings\": [\"foo\", \"bar\", \"bash\"]}]";
JSONAssert.assertEquals(expectedDataJSONArrayAsString, dataJSONArray, true);
// extract and verify data-strings
String dataStringsJSONArrayString = gson.toJson((ArrayList)response.then().extract().path("data[2].data-strings"));
JSONArray dataStringsJSONArray = (JSONArray) JSONParser.parseJSON(dataStringsJSONArrayString);
// JSONAssert - http://jsonassert.skyscreamer.org/
String expectedDataStringsJSONArrayAsString = "[\"foo\", \"bar\", \"bash\"]";
JSONAssert.assertEquals(expectedDataJSONArrayAsString, dataJSONArray, true);
// Json Schema Validation - https://jsonschema.net/
String dataStringsJsonSchemaString = "" +
"{\n" +
" \"type\": \"array\",\n" +
" \"definitions\": {},\n" +
" \"items\": {\n" +
" \"type\": \"string\",\n" +
" \"default\": \"\",\n" +
" \"examples\": [\n" +
" \"foo\",\n" +
" \"bar\",\n" +
" \"bash\"\n" +
" ]\n" +
" }\n" +
"}";
assertThat(dataStringsJSONArrayString, matchesJsonSchema(dataStringsJsonSchemaString));
//JsonPath responseJsonPath = JsonPath.parse(expectedDataStringsJSONArrayAsString);
JsonPath responseJsonPath = JsonPath.given(expectedDataStringsJSONArrayAsString);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment