Last active
December 1, 2018 23:45
-
-
Save rppowell-lasfs/522b2698825f362a83cf4af992c18800 to your computer and use it in GitHub Desktop.
API Testing Examples using TestNG, RESTAssured, JSONPath, JSONAssert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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