Difficulty: Beginner
Estimated Time: 15 minutes

Want to see how to test reactive components? We'll show you some examples!

This scenario builds on a previous scenario that shows you how to run the app, including setting up an Astra Cassandra database. If you haven't already done so, you may want to check it out.

The Reactive Spring Pet Clinic architectural stack consists of a controller, a services layer and the database. The controller handles API endpoint connections and uses the services layer to respond to API requests. The services layer interfaces with the database using Data Access Objects (DAOs).

Reactive Spring Pet Clinic architectural stack

An important principle of testing is isolating individual components. Isolating components has three major benefits:

  • Reduces dependencies and therefore test complexity
  • Facilitates pinpointing any malfunctions
  • Speeds up testing process

In this scenario, we'll show you how to isolate reactive components like the controller and services layer.

ver 0.006

This scenario showed you how to create and run the example Reactive Spring tests.

In this scenario, we:

  • Learned some basic BDD testing philosophy
  • Learned to mack the DAO layer and isolate the services layer
  • Learned to isolate and test the controller layer

Spring provides lots of tools to make testing easy - even for reactive apps!

Reactive Spring Pet Clinic Example

Step 1 of 3

Set up an Astra Cassandra Database

In this first step, let's build a simple test. We'll test the Owner class that the controller and services layer use to communicate. It's a simple class, but we'll use it to illustrate how to set up tests.

First, we need to enable tests in pom.xml. Click the following to open the file.

Open spring-petclinic-reactive/pom.xml

There is a property, maven.test.skip, that allows normal builds to skip the testing phase. scroll-down and make sure this property to false to enable the tests.

Now, we're ready to create the test. Let's start by creating a simple test program that just prints a statement. Initially, this program does not test anything, but it will allow us to figure out how to run tests.

Open a new file for a unit test named OwnerTest.java by clicking the following.

Open spring-petclinic-reactive/src/test/java/org/springframework/samples/petclinic/owner/OwnerTest.java

Let's take a quick look at our project directory structure. Click the following to run the tree command and inspect the output.

tree src

If you scroll up in the terminal, you see that there are two branches under the src directory: main and test. These two parallel directory structures allow us to keep the test classes separate from the produciton code so the tests don't get included with any jars we might want to create and deploy. As we might expect, OwnerTest.java resides under the test directory.

Add the initial contents to OwnerTest.java by clicking the following.

package org.springframework.samples.petclinic.owner;

import org.junit.jupiter.api.Test;

// Add more imports here

public class OwnerTest {

    @Test
    public void getters_should_return_correct_values() {
        System.out.println("***** Executing getters_should_return_correct_values() *****");

        // Given: the Owner's getter methods return these values supplied during construction

        // When: we construct an Owner with specific values

        // Then: the getters should return those values
    }
}

Take a minute to inspect this file. We see that the file contains a single class OwnerTest with a single method getters_should_return_correct_values(). This method merely prints out the method name.

We will use a Behavior Driven Development (BDD) philosophy for testing as indicated in the comments. This philosophy breaks the test into three parts:

  • Given specifies the conditions under which we will perform the test
  • When specifies the action we use to perform the test
  • Then specifies the expected outcome from the test

Also, notice the @Test annotation. This annotation indicates to JUnit what method(s) to run for the test. The import statement at the top gives OwnerTest access to the annotation.

Now, run the test by clicking the following.

mvn -Dtest=OwnerTest test

That's all there is to running a test! Notice that we specified the test class name on the Maven command line using the -D option. If we don't specify the test class name, Maven will run all tests.

Let's start filling in the various sections of the BDD test. In the Given section, we'll set up the values we will use. Click the following to add the values.

// Given: the Owner's getter methods return these values supplied during construction
        UUID id = UUID.fromString("11111111-1111-1111-1111-111111111111");
        String firstName = "John";
        String lastName = "Connor";
        String address = "T800 street";
        String city = "Detroit";
        String phone = "0123456789";

In the When section, we need to create an instance of Owner and use the given values. Click the following to add this code.

// When: we construct an Owner with specific values
        Owner o1 = new Owner(id, firstName, lastName, address, city, phone, new HashSet());

The code we just added is easy to understand - we construct an owner by supplying the various arguments. This code requires some additional import statements, so let's add those by clicking the following.

// Add more imports here
import java.util.HashSet;
import java.util.UUID;
import org.springframework.samples.petclinic.pet.Pet;

Our test still doesn't really test anything yet, but let's run it just to make sure everything compiles and runs as expected. Click the following.

mvn -Dtest=OwnerTest test

Let's fill out the Then section. This section needs to verify that the getter methods return the correct values. We'll use assertions to do that. Click the following to add the assertions, then take a minute to inspect this code and understand what it does.

// Then: the getters should return those values
        Assertions.assertThat(o1.getId()).isEqualTo(id);
        Assertions.assertThat(o1.getFirstName()).isEqualTo(firstName);
        Assertions.assertThat(o1.getLastName()).isEqualTo(lastName);
        Assertions.assertThat(o1.getAddress()).isEqualTo(address);
        Assertions.assertThat(o1.getCity()).isEqualTo(city);
        Assertions.assertThat(o1.getTelephone()).isEqualTo(phone);
        Assertions.assertThat(o1.getPets()).isEmpty();

This code also requires an additional import statement. Add the import by clicking the following.

// Add more imports here
import org.assertj.core.api.Assertions;

We are ready to run the test. Click the following.

mvn -Dtest=OwnerTest test

If we were to be thorough about our testing, we would probably want to test with multiple instances of Owner to make sure that none of the values get mixed up between instances, etc. We'll leave that as an exercise for you.

It might be interesting to see what it looks like when a test fails. Let's force a test failure just to see what happens.

Click the following to change the expected city from Detroit to Boston.

isEqualTo("Boston")

Now, run the test one more time and inspect the terminal output.

mvn -Dtest=OwnerTest test

Great! We understand some basic testing strategy as well as how to run tests!