Skip to content

API testing (Deprecated) ​

This research document is meant as a guideline on how to test the Flowcontrol REST-API.

API testing can be seen as the top level tests of the Flowcontrol BE (system tests). Where unit and integration tests test a part of the functionality or integration of the code, API tests test the whole functionality of the API (essentially the full BE).

By ensuring successful API tests, we can conclude that all functionality in the BE works as expected. When a test fails, we can conclude that the functionality is broken. API tests need supporting unit and integration tests on a lower level to discover the exact functionality (or piece of code) that is broken.

Required setup ​

Since these API tests are testing the full BE, we have decided to not include these in the CICD pipeline. This is because end to end tests are very slow and require the full BE system to be running. Achieving this in the CICD pipeline is not trivial and would require a lot of time to setup. Therefore we have decided to run these tests manually.

Before running the tests make sure that:

  • There is a running MSSQL Database in docker
  • There is a running Keycloak server in docker

When to run ​

Since these tests are very slow, we have decided to run these tests manually. This means that we run these tests when we want to test the full functionality of the BE. This is usually done before creating a merge/pull request or when a new feature is added. Developers are personally responsible for assuring code quality. When making big changes to the BE, it is advised to run these tests before creating a merge/pull request, but a developer can always run these tests locally to assure code quality during development.

Test data ​

Test data gets seeded into the running database on application start up. This is done by the Seeders that normally seed our database during development. The seeders use static values to seed the database. This means that the test data is always the same. Because of this, we use the same static data to assert the test results.

Documentation ​

Example ​

java
package flowcontrol.article.rest.controller;

import org.assertj.core.api.Assert;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ArticleControllerTest {

    //Static token value to skip authentication when testing
    private static final String token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ5TEpnenRfTTVNNjhrcVhHeDNKdGI0U3N6dGw3anlSODZEaktjTEFCOG44In0.eyJleHAiOjE2ODA5ODM3MDgsImlhdCI6MTY4MDk0NzcwOSwiYXV0aF90aW1lIjoxNjgwOTQ3NzA4LCJqdGkiOiI3NzgwYjkxNC03YjU5LTQ0ZDgtOTc4Yy00MGJjMmYzNDBmYjYiLCJpc3MiOiJodHRwOi8va2V5Y2xvYWstc2VydmljZTo4MTgwL3JlYWxtcy9GbG93Y29udHJvbCIsImF1ZCI6WyJyZWFsbS1tYW5hZ2VtZW50IiwiYWNjb3VudCJdLCJzdWIiOiIwYTU4MGQ4MS1hMTM4LTQ5YWYtODdlNy1hMmQwZTZiNjZlODEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJmbG93LWNvbnRyb2wiLCJzZXNzaW9uX3N0YXRlIjoiN2U4NzBlYjYtMTc4NC00NWY2LTg4ZTEtYTYwNDI3YmUyNDUxIiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImh0dHA6Ly8xOTIuMTY4LjE2LjE1NTo4MDgwIiwiaHR0cDovL2xvY2FsaG9zdDo4NzYyIiwiaHR0cDovLzE5Mi4xNjguMTYuMjQ6ODA4MCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1mbG93Y29udHJvbCIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJST0xFX1NVUEVSX0FETUlOIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJ2aWV3LXVzZXJzIiwicXVlcnktZ3JvdXBzIiwicXVlcnktdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiQ3VzdG9tX1VzZXJfQXR0cmlidXRlcyBlbWFpbCBwcm9maWxlIiwic2lkIjoiN2U4NzBlYjYtMTc4NC00NWY2LTg4ZTEtYTYwNDI3YmUyNDUxIiwiYmlydGhkYXkiOiIyMDAwLTAxLTI3IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImdlbmRlciI6Ik1hbGUiLCJpbWFnZV91cmwiOiJodHRwczovL2F2YXRhcnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3UvMjQ3MjQzNDc_dj00IiwiY3JlYXRlZF9hdCI6MTY3ODE4MDA3MTk3NiwicHJlZmVycmVkX3VzZXJuYW1lIjoibWFhcnRlbi5ob3JtZXMiLCJnaXZlbl9uYW1lIjoiTWFhcnRlbiIsInN0cmVldCI6IkthcmVsIERvb3JtYW5zdHJhYXQgM0MiLCJtb2JpbGVfcGhvbmUiOiIwNjE4Njg3MjgwIiwibmFtZSI6Ik1hYXJ0ZW4gSG9ybWVzIiwiZGVwYXJ0bWVudCI6IklDVCIsImZhbWlseV9uYW1lIjoiSG9ybWVzIiwiZW1haWwiOiJtYWFydGVuLmhvcm1lc0BsaW1heC5ubCJ9.H35MvQIxkvZBWOc-JzNIBM9FJN_xGW1mdqwpRXp5e3kVIa90u8LwYK36tY-cau3xuGN2tykxrRMBa12Efj2P_udg6z-ymBzySmY16gGTYS_7hUpZIP1umURebabMkalJgJBAaFJFAMXIFegzE4c8K8u6bxSklKxvP-FZD9DL28spQma-aNupApofoWknLJCqqBtMDHK9U3eXdKhqih609eTIzNeYdCWNTmjx8CnGzBonPJZn3zu_Qgl_RAlOamzSfwaoJ4kmhBKMmggC_jGZPjT-e2k0VMr4bRNVAu1yfQSjMUu0Y_YGwURRkyPxq8jlQOOMtjngGMtsjjqliqh_DA";

    //client used to send the request to the BE
    @Autowired
    private WebTestClient client;

    //Value of the random port the BE is running on
    @Value(value="${local.server.port}")
    private int port;

    @Test
    void testGetArticleById() {
        client.get().uri("/v1/articles/{id}", "29ef480b-2a00-4bc6-b97f-63b63e321c57")
                .accept(MediaType.APPLICATION_JSON)
                .headers(headers -> headers.setBearerAuth(token))
                .exchange()
                .expectStatus().isOk()
                .expectBody()
                .jsonPath("$.full_name").isEqualTo("Brown Wit Industrial 1 x 2500 CH052 Netherlands")
                .jsonPath("$._links.self.href").isEqualTo("http://localhost:"+port+"/article/api/v1/articles/29ef480b-2a00-4bc6-b97f-63b63e321c57");
    }

    @Test
    void testGetNameById() {
        //Call the API endpoint (with required parameters, headers, authentication, etc.)
        client.get().uri("/v1/articles/{articleId}/getname", "29ef480b-2a00-4bc6-b97f-63b63e321c57")
                .accept(MediaType.APPLICATION_JSON)
                .headers(headers -> headers.setBearerAuth(token))
                //actual call to endpoint
                .exchange()
                //check status of response
                .expectStatus().isOk()
                //check body of response
                .expectBody()
                //assert that the response body is equal to the expected value
                .consumeWith(response -> {
                  assertThat(response.getResponseBody()).isEqualTo("Brown Wit Industrial 1 x 2500 CH052 Netherlands".getBytes());
                });
    }
}