After sharing how we do automated testing on our fronted in my previous post I wanted to share too how we test our backend services using our API. You can find the extended version of this post in our blog
API/Integration tests must be faster to develop and run since they do not require any user interface to interact with since they directly hit the endpoints designed in your application.
The platform behind
Our backend platform follows the micro-service pattern, decomposing the application in small services that take care of one isolated piece of the whole business. We follow a hexagonal architecture (aka ports and adapters) to avoid having them highly coupled and facilitating testing activities. To expose all the endpoints we make use of APIs which are consumed by our BFFs using GraphQL.
Regarding the base code, it is written in PHP and it follows the Domain driven design (DDD) pattern. With all this what we have in the end are different bounded contexts (BCs) that completely isolate each side of the business.
The test tool
To test this we opted for Gauge which is an open source tool to write and run tests.
Gauge was created by ThoughtWorks and it is supported by a wide community. It can be used in any platform and it supports many languages for writing your test code. Two key features that we liked are that it’s BDD and it supports data-driven executions, making your tests more escalable.
For writing the tests scenarios themselves Gauge uses specification and concept files. Basically, specification files are those containing the scenarios written in a set of steps and concept files are just a collection of steps that you can reuse in the scenarios.
A spec file
Create Booking Request
======================
Tags: booking
Create booking request and charge (OK)
- - - - - - - - - - - - - - - - - - - - - - 
* Login with "test-user"
* Create a booking lead for listing id "999999" with move in "2021–01–01" and move out "2021–01–31"
* Create a booking request from booking lead
* Charge booking
* Wait until the booking request is converted into booking
This one above is an example of a specification file with one scenario written in Markdown language. The scenario just describes what they do in different steps. Each one of these steps has test code behind, but they can also relate to a concept file since they can be a set of steps themselves.
A concept file
# Charge booking
* JSON from file "./bookings/chargeBookingRequest.json" is set as variable "chargeJson"
* Set path "/payment/booking-requests/{id}/chargeNow" as name "charge" replacing path variable "{id}" with variable "bookingRequest"
* An HttpSampler with name "chargeBR" and path in variable "charge" and type "PUT" and port "xxx" and json "chargeJson"
* Response code is equal to "204"
Here we show an example for the step “Charge booking” that we presented in our spec file. You see all the steps behind that one, meaning that every time we call “Charge booking” from a spec file, all these steps will run.
We usually do that when:
- There are a lot of small steps required for just one high level task
- We do not want to show so much logic at the spec file level
- We are going to reuse such step in many test scenarios
Step implementation
Let’s show as an example the implementation for the step “An HttpSampler with name “chargeBR” and path in variable “charge” and type “PUT” and port “xxx” and JSON “chargeJson””
@Step("An httpSampler with name <name> and path <path> and type <type> and port <port> and json <json>")
public void setHttpSamplerNameTypePortBodyGiven(String name, String path, String type, Integer port, String json) {
// Java code to send an http request with the passed on parameters
}
Note the @Step
annotation. It denotes that the function is a step used in the spec files.
Build
To manage and build the project we use Maven. Maven is an extensively used build automation tool from Apache used in Java projects, although it can also be used for other languages. We’ve been working with it from the very beginning and it’s been useful to us given the big tree of dependencies that we have to maintain, both in-house and external ones.
Since we’ve got all our API tests in the same place, they are all placed in the same repository. So after updating our test collection, be it adding new tests or refactoring, the build is triggered just after pushing the changes to master branch to make sure all is fine. With that, we make available the latest version of the tests for the BCs to grab and run.
Setting up the CI
If you remember from our first post, we use Brigade as our CI system and our BCs use it in the same way. For every BC, we’ve got a Brigade file to indicate the events that must run in such pipeline.
With that, GitItNow (in-house developed tool), makes quite easy to interact with the pipeline and brings visibility to the whole process.
Above there’s one example of a pipeline for one of our BCs.
For the api-tests event it gets the latest successful build from the test repository and runs it.
Worth mentioning too that we have enabled parallelization in our Ci runs to be able to run them faster and react soon in case anything goes wrong.
Summary
With all commented here, we ended up with a robust framework that enables us to track the quality of the backend code we deploy and react soon in case a red flag shows up. Is it perfect? Nope (I'd say nothing is). We still deal with collateral issues such as stuck queues or false positives due to misleading data or other kind of human errors. But there are also some other aspects such as the escalability that a BDD approach gives us, getting to a point where there are so many steps developed that we almost don't need to develop more but use what exists.
Hope you enjoyed the post 🚀
Top comments (1)
Hello David. Can you please give me some suggestions on how did you start learning backend automation? The article here primarily discusses on how you built an environment to test the backend of the application according to requirements. I want to know how did you start learning it. I am an QA Automation Engineer myself. But my only testing scope is around frontend in my company. So, I want to broaden my skills in backend too. Any help will be highly appreciated!