Hey there! I just wanna hear some more opinions on testing services in order to ensure they are communicating with each other as expected.
For the foundation of the discussion let's assume we have three separate services.
Service A: Handles HTTP Requests, proxies requests to
Service B; sends job requests to
Service B: Returns a result based on data that has been processed by
Service C: Processes some data and writes it somewhere else; receives job requests from
Let's first talk through how a scenario could look like:
- User sends HTTP request to
Service Atries to load data from
Service Btries to load data from a database
- Data is non-existing in the database
Service Athat the data is not available
Service Cthat it should fetch the data
Service Ainforms User that the data is currently not available and he should retry later
We can (and probably should) test the public API of each service in isolation as a single unit.
We need to mock all the other services
If services are directly dependent e.g. by HTTP requests we need to spin up a server that sends back expected responses.
Will the service run in production?
How can we ensure that a Node.js application is still working when put inside a docker container for production deployment, e.g. we could have forgotten to install a dependency and it will fail on startup?
In order to guarantee this, we actually have to spin up the container and test its functionality before deploying it.
How can we ensure that two services are actually able to communicate with each other?
The tests could get out of sync because one person changed
Service B but forgot to apply the changes to the test of
Service A. The
Service B-mock for the
Service A-test is now wrong.
Both are no longer able to communicate with each other.
Testing each service in isolation actually gives us no guarantee that both services will be able to communicate with each other in production.
In addition to writing tests for each service, we could also have some tests that spin up all our services and check whether they are able to deliver a result.
We now have to orchestrate different services and make sure they are all up and running (and healthy) before our tests start.
Luckily there are libraries like dockest (jest + docker containers) that help spinning up containers and to make sure the containers are ready before running the tests and other stuff like automatically failing tests in case a container unexpectedly dies.
However, CI duration can now drastically increase, because besides testing each container in isolation we now test them as a whole stack. It could increase even further in case the containers do some very complex and time-intensive tasks, like loading something from a data source, transforming it and writing it to a different data source.
One solution to that problem would be using smaller datasets than in production.
Complex service interaction seems to be a very hard thing to test. Maybe we should try to avoid separating our products into different services, but sometimes there is no other option available.
We still need to do the testing in order to be sure our production system will not fail, due every service working fine in isolation but not in synergy with the other services.
I am curious about your input on this topic!
How do you ensure separate services are able to communicate with each other?
What tools do you use to do so?