“Local Test Environment”-as-Code
Automate Everything, even the setup of your local test environment.
Let’s assume your team is building a solution for the SAP Cloud Platform, Cloud Foundry environment. The solution consists of multiple components communicating with each other(we want to be fashionable, so let’s call them microservices).
But you are working on one single microservice and want to be able to test it in isolation, on your local computer.
Very quickly you realize that your microservice has multiple dependencies that must be managed if you want to be able to test one service locally. Here are some examples:
- You need a database to persist data
- Async. communication between microservices requires a messaging service like RabbitMQ to be available
- Your service has dependencies to other microservices and/or external services
- You are using the Fiori Launchpad as a central point of entry, and need a local Launchpad instance to handle things like authentication
Of course, your first instinct will be to hack your way through the problems and manually:
- Download the first Postgresql and RabbitMQ servers you find and install them onto your computer
- Download and run all downstream services on your computer as well
Here’s why that’s not a good idea:
A. Manually setting up environments this way is a surefire way to turning your computer into a “snowflake”: A unique environment which is different from “staging”, different from “production” and different from that of every other member of your team. It’s only a matter of time until you run into problems and start yelling “But it worked on my machine!”
B. You’re not alone in this. If you have this problem most likely others have it too, they just did not speak up about it (yet). Take the time and find a reusable solution, others will thank you for it
C. Your test environment is like a living creature, requiring constant maintenance and adaptions. When performed manually on every computer, changes are painful and time-consuming. Instead establish a process for adding changes and rolling them out to your team smoothly.
A better approach
So instead of choosing the quick-and-dirty approach, why not make a one-time investment to set up a proper local testing environment? But what does “proper” mean? This is debatable, but here are some guidelines:
- A proper test environment is fully automated, i.e. it can be started up easily (ideally using just one command), in a reproducible manner
- A proper test environment is centrally managed, i.e. changes are performed once and automatically rolled out to all users
- A proper test environment is isolated, leaving no side-effects and assuring a consistent behavior
- A proper test environment resembles production as much as possible
What is “Local Test Environment”-as-Code supposed to mean?
In order to execute recurring tasks in a repeatable & reliable manner, it’s common practice to define everything “-as-Code”. I.e. as scripts or config files that automate the task and which can be shared as part of the source code repository: Infrastructure-as-Code, Pipeline-as-Code, Configuration-as-Code etc.
Similarly, “Local Test Environment”-as-Code would be a script that automates the setup of your local test environment. In our case it implies creating a stripped-down virtual Cloud Foundry environment, providing just enough features to enable isolation testing of one microservice on your local computer, i.e.:
- Providing all necessary backing services
- Providing all necessary downstream services (or even better, stubs thereof!)
- Providing a local Fiori Launchpad or AppRouter instance to handle authentication & routing
- Starting the service under test in a custom environment (by setting environment variables the way CF would)
All good, but where do I start?
If you read this, want to apply the concepts to your own project, but don’t exactly know where to start, here’s a small repo to get you kickstarted: https://github.com/ionescuv/sap-cp-cf-devbox
I called it SAP CP Cloud-Foundry DevBox, since it is designed specifically for apps running on the SAP Cloud Platform Cloud Foundry environment. (although plain vanilla Cloud Foundry apps can also benefit from it)
- common backing services provided through a Vagrant box: Postgresql DB + Web-based DB client, RabbitMQ instance, Swagger UI
- Spawning processes using a custom environment, to easily mimic the Cloud Foundry environment
- A locally running Fiori Launchpad, that can use remote UAA & Portal service instances for authentication & tile configuration
- integration of WireMock stubs (powered by Spring-Cloud-Contract) to replace downstream dependencies with stubs
- a small CLI to bundle everything together
Or if you prefer the graphical variant:
**Side note**: there are also some very neat CF CLI plugins out there, of which I will mention cflocal, cfdev & copyenv, which might also come in handy for addressing the issues discussed in this post. They might be worth looking into if you are developing on Linux and/or have native Docker support on your OS.