Develop and Test Spring Boot Applications Consistently
Dan Dobrin
Enterprise App Modernization Architect
You do not have to burden yourself anymore with a long list of manual steps required to setup an application locally, test with an in-memory database, sift through discrepancies between environments and SQL dialects or not being able to test network failures typical for a distributed system.
When building Twelve-factor Google Cloud applications, developers are looking for a consistent way to develop, debug and test locally with the same containerized application dependencies as they would run in production in GCP, the environment parity from Dev to Prod - factor Ten on the list of twelve-factor apps.
Google’s Java Cloud Client Libraries and Spring Cloud GCP make migrating, or building a new cloud-native, production-ready Spring Boot application a breeze, with developers able to quickly spin up the application and focus on building out the business logic.
In this blog post we’ll focus on significantly improving (and speeding up) your development experience for Google Cloud Spring Boot Java Applications, with a consistent way to develop, debug and test locally, following the goal of environment parity from Development-to-Production in Google Cloud.
Google Cloud Emulators, Testcontainers and Spring Boot to the rescue
Testcontainers is an open source framework for providing throwaway, lightweight instances of databases, message brokers, web browsers, or any other custom Docker container. There is no more need for mocks or complicated environment configs. Testcontainers allow you to define your test dependencies as code, then simply run your tests and containers will be created and then deleted at the end of the test lifecycle.
Google’s Cloud SDK provides libraries and tools for interacting with the products and services provided by the Google Cloud Platform. Testcontainers modules are preconfigured containerized implementations of various dependencies that make writing your tests very easy.
Currently, Testcontainers Google Cloud Module supports Bigtable, Datastore, Firestore, Spanner, and Pub/Sub GCP Emulators in Java and other languages.
Spring Boot 3.1 has added Testcontainers support, allowing you to configure all application dependencies (databases, messaging systems, caching mechanisms, dependent services) to start automatically when you run or test the application locally.
If you are looking to learn more about how to test your Spring Boot applications with Testcontainers, follow this Getting started guide.
Development tasks
Before we dive into details, let’s revisit the some of the tasks you would usually address as a developer:
Write Unit Tests for individual pieces of functionality, say classes/methods
Write (Domain) Service Integration Tests to test domain operations and business rules, including the Integration with dependent applications or cloud services
Write Application Tests to functionally test your application and its web controllers
Write Network Failure Tests to assess that the source code will handle any such failure, part of chaos engineering best practices
Local Development with app dependencies
Blog Source Code
This blog post is supported by a full set of Spring Boot sample apps, with tests highlighting the usage of Cloud Firestore and open-source Postgres (for Cloud SQL) Testcontainers.
Clone the Git repository and follow along in the Audit (Firestore) and Quotes (Postgres) services to gain hands-on experience with the concepts exposed herein. The following material will continue on the Firestore usage path.
Test configuration
First, add the spring-boot-testcontainers
as a test dependency to your Maven pom.xml:
Next, add the Google Client Libraries Bill-of-Materials(BOM) for compatibility across more than 200 Google Java libraries:
Last, add the dependency on the respective application dependent service:
To test with the testcontainer for the Firestore emulator, configure the @Container and provide its dynamic properties in the test class.
Ex: Firestore Service Test [test]
Note that Spring Boot 3.1 has added the concept of Service Connections, which automatically configures the necessary Spring Boot properties for the supporting containers.
A Postgres configuration would be reduced to:
Writing (Domain) Service/Integration Tests
Testing your service against a containerized Firestore emulator provides the confidence that the code will run smoothly in Cloud Firestore: [test]
Writing Application Tests
Writing application tests allows you to test your app as you would run it in a cloud environment in Prod.
For example, your service is running in a Serverless environment and is a component of an event-driven architecture. CloudEvents is a specification for describing event data in a common way and you can now test your HTTP call with CloudEvents in the web controller, while leveraging Firestore testcontainers: [test]
Writing Network Failure tests
Network failure conditions between services running in the cloud present one of the highest risks in distributed software, since they directly affect service delivery. Before running your services in cloud environments, you want to test the resiliency of your service client code in your codebase for any such random disruptions, which can cause applications to respond unpredictably and break under pressure.
These tests are part of Chaos Engineering best practices.
To simulate network failure conditions, you can place Shopify’s Toxiproxy container in between test code and a container, or in between containers. [test]
You can now simulate timeouts due to latency, retries or dropped network connections.
For example, you can test with a simulated timeout as follows:
Local Development with application dependencies
Starting with Spring Boot 3.1, you can also use Testcontainers during your regular dev time for running and debugging the application locally with your respective dependent services!
There is no need to do any extra work, just configure a TestAuditApplication and TestcontainersConfig class in your test classpath under /src/test/java
and start your app.
Note that the app is started with the TestcontainersConfig class attached to the application launcher using .with(TestcontainersConfig)
:
You can run the TestAuditApplication from your IDE or simply with:
Summary
By using Google Cloud Emulators, Testcontainers and Spring Boot 3.1, you can significantly improve (and speed-up) your development experience for Google Cloud Applications, with a consistent way to develop, debug and test locally with the same containerized application dependencies as you would run in production in Google Cloud — the environment parity from Dev to Prod.
Check out the codebase, if you want to get more hands-on experience with Spring Boot Applications using Google Cloud Emulators and Testcontainers.
For questions or feedback, feel free to contact me on Twitter @ddobrin.