Slide 1

Slide 1 text

API Testing Break your API before your customer does Sergey Zenchenko CTO

Slide 2

Slide 2 text

• > 100 endpoints • ~ 40 team members • 2 mobile platforms + backend • Micro-services architecture • Need for tests Given

Slide 3

Slide 3 text

Evolution

Slide 4

Slide 4 text

Codeception • PHP sucks • Concurrency support is limited • API client is low level and verbose • Hard to maintain large test suite • No static typing • Code is not reusable codeception.com

Slide 5

Slide 5 text

Runscope • UI Based • Slooooow • Hard to maintain large test suite • Code is not reusable runscope.com

Slide 6

Slide 6 text

Mocha/Supertest/ Chakram • API client is low level and verbose • Concurrency support is limited • Hard to maintain large test suite • No static typing • Code is not reusable https://mochajs.org https://github.com/visionmedia/supertest http://dareid.github.io/chakram/

Slide 7

Slide 7 text

Bright future

Slide 8

Slide 8 text

Requirements • Parallel execution • Simple test structure. No async in tests • Test should operate with business domain, not with HTTP requests • Work with Objects not JSON and Strings • Static typing • Code reusability

Slide 9

Slide 9 text

Java to the rescue! • Already used in the Android app for UI tests • Can be shared between multiple components • Good concurrency support • Mature test frameworks

Slide 10

Slide 10 text

Main components • Test framework • Domain models • API Client • Support: assertions frameworks, reporting tool, etc

Slide 11

Slide 11 text

TestNG • xUnit style • Parallel test execution • Powerful concurrency management using method and group dependencies • Nice features like data providers testng.org

Slide 12

Slide 12 text

Models • Request models • Response models • Assertions for models attrs., not for JSON/XML attrs. Never work with raw data • Response structure validation should be done by model parser, not by humans

Slide 13

Slide 13 text

POJOs More samples
 See https://github.com/techery/janet-sample-api-integration public class User { int id; String param; }

Slide 14

Slide 14 text

Immutable Objects More samples
 See https://github.com/techery/janet-sample-api-integration http://immutables.github.io @Value.Immutable @Gson.TypeAdapters public interface User { @SerializedName("name") String name(); @SerializedName("id") int id(); }

Slide 15

Slide 15 text

Assert for models More samples
 See https://github.com/techery/janet-sample-api-integration assertThat(user.name()).isEqualTo("John"); assertThat(jsonUser.getString("name")).isEqualTo("John"); VS

Slide 16

Slide 16 text

API Client

Slide 17

Slide 17 text

REST-Assured • Simple DSL • Designed especially for testing • POJO support • Might be too low level sometimes • No code reuse :( rest-assured.io

Slide 18

Slide 18 text

REST-Assured sample More samples
 See https://github.com/techery/janet-sample-api-integration given(). param("text", “hey"). param("title", “Amazing post"). when(). post("/posts"). then(). statusCode(201);

Slide 19

Slide 19 text

Retrofit • One of the most popular API frameworks for Java • Code can be reused outside of test project • Can use POJOs • Not flexible enough sometimes square.github.io/retrofit/

Slide 20

Slide 20 text

Retrofit sample More samples
 See https://github.com/techery/janet-sample-api-integration public static class BlogPost { public int id; public String title; public String text; } public interface BlogAPI { @POST("/posts") BlogPost create(@Field("title") String title, @Field("text") String text); } void testBlogPosting() { String title = "Amazing post"; String body = "hey"; BlogPost blogPost = blogAPI.create(title, body); assertThat(blogPost.text, equals(title)); }

Slide 21

Slide 21 text

Janet • Command based service layer • Protocol agnostic • Based on reactive programming approach • Can be used for HTTP with janet-http service • Can be used in any JVM app github.com/techery/janet

Slide 22

Slide 22 text

Janet Action • Java class that describes operation • Each API request is a separate Janet Action • Purely declarative • Annotations are used to map class attrs. to HTTP request values • Action are executed by services. (HTTPService, WebSocketService, SOAPService, YourCustomService)

Slide 23

Slide 23 text

Let’s test something /health_check?url={url} { is_available:boolean, response_time:number }

Slide 24

Slide 24 text

Step 0: setup project More samples
 See https://github.com/techery/janet-sample-api-integration Skip

Slide 25

Slide 25 text

Step 1: define action More samples
 See https://github.com/techery/janet-sample-api-integration @HttpAction(value = "/health_check", method = HttpAction.Method.GET) public class HealthCheckAction { @Query("url") public final String url; public HealthCheckAction(String url) { this.url = url; } @Response public HealthStatus response; }

Slide 26

Slide 26 text

Step 2: define model More samples
 See https://github.com/techery/janet-sample-api-integration public class HealthStatus { @SerializedName("is_available") public Boolean isAvailable; @SerializedName("responseTime") public float responseTime; }

Slide 27

Slide 27 text

Step 3: write test More samples
 See https://github.com/techery/janet-sample-api-integration public class HealthCheckTest { Janet janet; void testHealthCheck() { String originalURL = "https://techery.io/jobs"; final ActionPipe pipe = janet.createPipe(HealthCheckAction.class); final Observable> observable = pipe.createObservable(new HealthCheckAction(originalURL)); HealthCheckAction action = observable.toBlocking().last().action; HealthStatus response = action.response; assertThat(response).isNotNull(); assertThat(response.isAvailable).isTrue(); assertThat(response.responseTime).isLessThan(100.0f); } }

Slide 28

Slide 28 text

Step 3: write test with some helpers More samples
 See https://github.com/techery/janet-sample-api-integration public class HealthCheckTest extends BaseTest { void testHealthCheck() { String originalURL = "https://techery.io/jobs"; HealthCheckAction action = execute(new HealthCheckAction(originalURL)); HealthStatus response = action.response; assertThat(response).isNotNull(); assertThat(response.isAvailable).isTrue(); assertThat(response.responseTime).isLessThan(100.0f); } }

Slide 29

Slide 29 text

Protocol Agnostic • HTTP • WebSockets • TCP sockets • Etc

Slide 30

Slide 30 text

Step 1: define action More samples
 See https://github.com/techery/janet-sample-api-integration @WsAction(event = "health_check") public class HealthCheckAction { @Payload("url") public final String url; public HealthCheckAction(String url) { this.url = url; } @Response public HealthStatus response; }

Slide 31

Slide 31 text

Step 2: define model More samples
 See https://github.com/techery/janet-sample-api-integration public class HealthStatus { @SerializedName("is_available") public Boolean isAvailable; @SerializedName("responseTime") public float responseTime; }

Slide 32

Slide 32 text

Step 3: write test with some helpers More samples
 See https://github.com/techery/janet-sample-api-integration public class HealthCheckTest extends BaseTest { void testHealthCheck() { String originalURL = "https://techery.io/jobs"; HealthCheckAction action = execute(new HealthCheckAction(originalURL)); HealthStatus response = action.response; assertThat(response).isNotNull(); assertThat(response.isAvailable).isTrue(); assertThat(response.responseTime).isLessThan(100.0f); } }

Slide 33

Slide 33 text

Sample code https://github.com/techery/janet-sample-api-integration Sample Android app with API client library and tests

Slide 34

Slide 34 text

API development workflow 1. New API feature request 2. Team defines models and actions 3. Team writes tests for new endpoint 4. Android team can now start implementing feature by mocking actions if required. 5. Tests run on CI to check if feature is working 6. Backend team deploys new API endpoint 7. Tests pass and feature is ready

Slide 35

Slide 35 text

API development workflow Actions and Models serve as an API contract and every team member can contribute to it

Slide 36

Slide 36 text

Platform structure Janet based API Client Android app API tests UI tests API docs (in beta) iOS Client (in future)

Slide 37

Slide 37 text

Links • https://github.com/techery/janet-sample-api- integration • https://github.com/techery/janet-sample-api- integration • https://github.com/techery/janet-http • http://testng.org/doc/documentation- main.html • http://immutables.github.io

Slide 38

Slide 38 text

We are hiring! techery.io/jobs