Reader small image

You're reading from  Microservices with Spring Boot 3 and Spring Cloud, Third Edition - Third Edition

Product typeBook
Published inAug 2023
Reading LevelIntermediate
PublisherPackt
ISBN-139781805128694
Edition3rd Edition
Languages
Right arrow
Author (1)
Magnus Larsson
Magnus Larsson
author image
Magnus Larsson

Magnus Larsson, an IT industry veteran since 1986, has consulted for major Swedish firms like Volvo, Ericsson, and AstraZeneca. Despite past struggles with distributed systems, today's open-source tools like Spring Cloud, Kubernetes, and Istio offer effective solutions. For the past eight years, Magnus has been helping customers use these tools and shared insights through presentations and blog posts.
Read more about Magnus Larsson

Right arrow

Adding automated microservice tests in isolation

Before we wrap up the implementation, we also need to write some automated tests.We don't have much business logic to test at this time, so we don't need to write any unit tests. Instead, we will focus on testing the APIs that our microservices expose; that is, we will start them up in integration tests with their embedded web server and then use a test client to perform HTTP requests and validate the responses. With Spring WebFlux comes a test client, WebTestClient, that provides a fluent API for making a request and then applying assertions on its result.The following is an example where we test the composite product API by doing the following tests:

  • Sending in productId for an existing product and asserting that we get back 200 as an HTTP response code and a JSON response that contains the requested productId along with one recommendation and one review
  • Sending in a missing productId and asserting that we get back 404 as an...

Adding semi-automated tests of a microservice landscape

Being able to automatically run unit and integration tests for each microservice in isolation using plain Java, JUnit, and Gradle is very useful during development, but insufficient when we move over to the operation side. In operation, we also need a way to automatically verify that a system landscape of cooperating microservices delivers what we expect. Being able to, at any time, run a script that verifies that a number of cooperating microservices all work as expected in operation is very valuable – the more microservices there are, the higher the value of such a verification script.For this reason, I have written a simple bash script that can verify the functionality of a deployed system landscape by performing calls to the RESTful APIs exposed by the microservices. It is based on the curl commands we learned about and used above. The script verifies return codes and parts of the JSON responses using jq. The script contains...

Summary

We have now built our first few microservices using Spring Boot. After being introduced to the microservice landscape that we will use throughout this book, we learned how to use Spring Initializr to create skeleton projects for each microservice.Next, we learned how to add APIs using Spring WebFlux for the three core services and implemented a composite service that uses the three core services' APIs to create an aggregated view of the information in them. The composite service uses the RestTemplate class in the Spring Framework to perform HTTP requests to APIs that are exposed by the core services. After adding logic for error handling in the services, we ran some manual tests on the microservice landscape.We wrapped this chapter up by learning how to add tests for microservices in isolation and when they work together as a system landscape. To provide controlled isolation for the composite service, we mocked its dependencies to the core services using Mockito. Testing...

Questions

  1. What is the command that lists available dependencies when you create a new Spring Boot project using the spring init Spring Initializr CLI tool?
  2. How can you set up Gradle to build multiple related projects with one command?
  3. What are the @PathVariable and @RequestParam annotations used for?
  4. How can you separate protocol-specific error handling from the business logic in an API implementation class?
  5. What is Mockito used for?

Using Docker with one microservice

Now that we understand how Java works in a container, we can start using Docker with one of our microservices. Before we can run our microservice as a Docker container, we need to package it in a Docker image. To build a Docker image, we need a Dockerfile, so we will start with that. Next, we need a Docker-specific configuration for our microservice. Since a microservice that runs in a container is isolated from other microservices – it has its own IP address, hostname, and ports – it needs a different configuration compared to when it’s running on the same host with other microservices.

For example, since the other microservices no longer run on the same host, no port conflicts will occur. When running in Docker, we can use the default port 8080 for all our microservices without any risk of port conflicts. On the other hand, if we need to talk to the other microservices, we can no longer use localhost like we could when...

Managing a landscape of microservices using Docker Compose

We’ve already seen how we can run a single microservice as a Docker container, but what about managing a whole system landscape of microservices?

As we mentioned earlier, this is the purpose of docker-compose. By using single commands, we can build, start, log, and stop a group of cooperating microservices running as Docker containers.

Changes in the source code

To be able to use Docker Compose, we need to create a configuration file, docker-compose.yml, that describes the microservices Docker Compose will manage for us. We also need to set up Dockerfiles for the remaining microservices and add a Docker-specific Spring profile to each of them. All four microservices have their own Dockerfile, but they all look the same as the preceding one.

When it comes to the Spring profiles, the three core services, product-, recommendation-, and review-service, have the same docker profile, which only specifies that...

Automating tests of cooperating microservices

Docker Compose is really helpful when it comes to manually managing a group of microservices. In this section, we will take this one step further and integrate Docker Compose into our test script, test-em-all.bash. The test script will automatically start up the microservice landscape, run all the required tests to verify that the microservice landscape works as expected, and finally, tear it down, leaving no traces behind.

The test script can be found at $BOOK_HOME/Chapter04/test-em-all.bash.

Before the test script runs the test suite, it will check for the presence of a start argument in the invocation of the test script. If found, it will restart the containers with the following code:

if [[ $@ == *"start"* ]]
then
    echo "Restarting the test environment..."
    echo "$ docker-compose down --remove-orphans"
    docker-compose down --remove-orphans
    echo "$ docker-compose up -d"...

Summary

In this chapter, we have seen how Docker can be used to simplify testing a landscape of cooperating microservices.

We learned how Java SE, since v10, honors constraints that we put on containers regarding how much CPU and memory they are allowed to use. We have also seen how little it takes to make it possible to run a Java-based microservice as a Docker container. Thanks to Spring profiles, we can run the microservice in Docker without having to make any code changes.

Finally, we have seen how Docker Compose can help us manage a landscape of cooperating microservices with single commands, either manually or, even better, automatically, when integrated with a test script such as test-em-all.bash.

In the next chapter, we will study how we can add some documentation of the API using OpenAPI/Swagger descriptions.

Questions

  1. What are the major differences between a virtual machine and a Docker container?
  2. What is the purpose of namespaces and cgroups in Docker?
  3. What happens with a Java application that doesn’t honor the max memory settings in a container and allocates more memory than it is allowed to?
  4. How can we make a Spring-based application run as a Docker container without requiring modifications of its source code?
  5. Why will the following Docker Compose code snippet not work?
      review:
        build: microservices/review-service
        ports:
          - "8080:8080"
        environment:
          - SPRING_PROFILES_ACTIVE=docker
      product-composite:
        build: microservices/product-composite-service
        ports:
          - "8080:8080"
        environment:
          - SPRING_PROFILES_ACTIVE=docker
    
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Microservices with Spring Boot 3 and Spring Cloud, Third Edition - Third Edition
Published in: Aug 2023Publisher: PacktISBN-13: 9781805128694
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Magnus Larsson

Magnus Larsson, an IT industry veteran since 1986, has consulted for major Swedish firms like Volvo, Ericsson, and AstraZeneca. Despite past struggles with distributed systems, today's open-source tools like Spring Cloud, Kubernetes, and Istio offer effective solutions. For the past eight years, Magnus has been helping customers use these tools and shared insights through presentations and blog posts.
Read more about Magnus Larsson