Getting Started with the Component Test Framework

Lydtech

A tutorial walking us through using the Component Test Framework to add a component test to the Simple Service, a REST based stripped back microservice

What is the Component Test Framework?

The component test framework is an open source framework which orchestrates the running of component tests, by spinning up the application under test and its external dependencies in Docker containers.

All code for this tutorial can be found on GitHub:
CTF Getting Started

What is Component Testing?

We use component testing to exercise some use cases that allow us to verify the component under test is ready to be integrated with the wider system. In our example we exercise a service call that results in the query of a downstream system. The component test validates that the service stands up correctly and is able to engage with external components (be these in mock or real form).

Simple Service Overview

The service we are working with has been stripped back as far as possible so that we can focus on the component test.

Our simple service contains a REST controller with a single endpoint. The correct invocation of this endpoint will result in Simple Service making a REST call to the third party service. Our goal with the component test is to verify that this call is successful.

To achieve this we must start the Simple Service and the components it requires. In this example, the Third Party Service must also be started. Because external services may be unreliable or costly, we use a mock.

Simple Service and Third Party Integration

To reassure ourselves that the service is built correctly and can start in isolation, we mock the external dependencies. Our component test setup will look like this:

Simple Service under Component Test

There are 3 steps to enabling testing of the service with the component test framework:

  1. Dockerize the service under test
  2. Enable the component test framework. This involves:
    • Build file changes (Maven or Gradle – we use Maven)
    • Define the mock (specific to this REST example)
  3. Create and run the test

Simple Service - Our service under test

This is our service under test, stripped back to make it easy to see how the test is working.

The service has a single REST endpoint:

@PutMapping("/users/{id}/mood/{mood}")
public Mood updateUserMood(@PathVariable Mood mood, @PathVariable Long id) {
   userMoodService.processUserMood(mood);
   return mood;
}

There are only 3 Moods defined: HAPPY, INDIFFERENT, and GRUMPY.

The UserMoodService makes the third party call:

public void processUserMood(Mood mood) {
    if (mood == Mood.GRUMPY || mood == Mood.HAPPY ) {
        callThirdparty(mood.toString());
    }
}

To run the service:

mvn spring-boot:run

To call the endpoint:

curl -i -X PUT http://localhost:8080/users/1/mood/INDIFFERENT

Notes:

  1. We deliberately do not test HAPPY and GRUMPY here, as those require the third party service.
  2. The {id} value is arbitrary. No users are persisted.

Step 1 - Dockerize the service

We use the Spring Boot Maven plugin to create the Docker image:

mvn spring-boot:build-image

Step 2 - Enable the Framework

Define the Mock

We use Wiremock to mock the third party REST service.

Example health check endpoint config:

{
 "request": {
   "method": "GET",
   "url": "/health"
 },
 "response": {
   "status": 204
 }
}

Third-party endpoint config:

{
 "request": {
   "method": "GET",
   "urlPattern": "/api/thirdparty/.*"
 },
 "response": {
   "status": 200,
   "headers": {
     "Content-Type": "text/plain"
   },
   "body": "Success"
 }
}

Pull in and Configure the Framework

Add to pom.xml:

<dependency>
    <groupId>dev.lydtech</groupId>
    <artifactId>component-test-framework</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Add surefire plugin config:

<profile>
  <id>component</id>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>*CT.*</include>
          </includes>
          <environmentVariables>
            <TESTCONTAINERS_REUSE_ENABLE>${containers.stayup}</TESTCONTAINERS_REUSE_ENABLE>
          </environmentVariables>
          <systemPropertyVariables>
            <service.name>${project.name}</service.name>
            <wiremock.enabled>true</wiremock.enabled>
          </systemPropertyVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>
</profile>

Step 3 - Create and Run the Test

Define the Test Class

@ExtendWith(ComponentTestExtension.class)
public class CallThirdPartyApiCT {

Setup Method

@BeforeEach
public void setup() {
   WiremockClient.getInstance().deleteAllRequestsMappings();
   serviceBaseUrl = ServiceClient.getInstance().getBaseUrl();
   RestAssured.baseURI = serviceBaseUrl;
}

Test Method

@Test
public void testThirdPartyEndpointIsCalled() {
   Response response = put("/users/1/mood/HAPPY");
   log.info("Response: {}", response.getStatusCode());

   RequestCriteria request = RequestCriteria.builder()
           .method("GET")
           .url("/api/thirdparty/HAPPY")
           .build();
   WiremockClient.getInstance().countMatchingRequests(request, 1);
}

Run the Component Test

mvn test -Pcomponent

The framework starts all required containers, waits for readiness via /health, and then runs the tests.

What Not to Component Test

Component tests are time expensive – prefer to validate business logic in unit tests.

Example logic:

if (mood == Mood.GRUMPY || mood == Mood.HAPPY ) {
   callThirdparty(mood.toString());
}

Only one component test is needed (e.g. for HAPPY). The rest can be covered by unit tests.

What next?

Apply these learnings to your own project and start using component testing today!

The framework also supports:

  • Kafka
  • Debezium (Kafka Connect)
  • Kafka Schema Registry
  • Conduktor Gateway (Kafka chaos testing)
  • Elasticsearch
  • Postgres
  • Mongo
  • DynamoDB
  • MariaDB

📦 Component Test Framework on GitHub

Check out the framework directly or the Lydtech pages to find more detail on integrations

Component Test Framework