What are API service tests?
With an ever increasing list of names given to testing approaches, it can sometimes be a struggle to remember exactly what service tests are. It may even be that the term ‘service test’ has a different meaning to you and I, so for the purposes of this post, my definition is as follows:
A suite of service tests or contractual tests allow a developer to confidently develop and refactor an API whilst remaining confident that the API is functioning as intended (i.e. you won’t introduce bugs as you develop)
Why even use service tests?
In an age where micro-services are becoming increasingly popular, (where an application may have a separate frontend, API, backend, etc..), it’s becoming more and more important to test those services independently.
If you’re developing an API for a product it’s likely you’ll strike a contract with a frontend application to define how the API will work. Using service tests can help to verify that when you develop/extend/refactor your API you’re still fulfilling the contract between the API and frontend; that’s why service tests can also be known as contract tests.
Problems we’ve had in the past
We’ve been practicing TDD (test driven development) at UVD for a number of years now and service tests play a large part in some of our projects. We recently underwent a huge refactor of Limpid Markets, which is one of our largest projects and having our service tests, along with unit and acceptance tests meant we could refactor with confidence.
Currently, the service test suite for our NodeJS API is run using PHP’s Behat, with a Gherkin feature file for each of our endpoints. At the time of choosing the technologies, Behat was the right choice (because of expertise and a lack of Node options), but recently I’ve had a few frustrations.
The first was that it would take around 18 minutes to run the full suite of tests and there were also a few tasks that needed to be run before running the test suite e.g. exporting a NODE_PATH.
I recently took it upon myself to redevelop the NodeJS API for our Coffeestats internal project and I was determined to find a nicer strategy for creating and maintaining service tests.
Ermm what’s Coffeestats?
Before I deep dive into service tests in Node and some examples from our API, its probably wise to give a bit of a description as to what Coffeestats is!
Coffeestats is an internal project that we created to monitor how much coffee we’re drinking and if it affects our productivity. Every time someone in the office makes themself, (or if they’re feeling generous, others) a coffee, they record how many were made via the interface running on an iPhone next to the coffee machine.
Over the years we’ve gathered quite a bit of data and if your interested in our drinking habits you can find our stats here.
Advantages of running service tests in Node
Straight off the bat there were a number of advantages I found when approaching the testing strategy from a NodeJS only perspective. The speed in which the tests would run was a big bonus and although the size of the Coffeestats API was small in comparison to the large API that’s used in Limpid Markets, I’m confident that it will remain lightning quick.
API service tests with `supertest`
Getting into the nitty gritty of exactly what libraries I used in my testing strategy for the new Coffeestats API, I began by looking for some NodeJS based testing tools for developing API’s and I came across SuperTest.
In the developer’s words, SuperTest is a “a high-level abstraction for testing HTTP, while still allowing you to drop down to the lower-level API provided by super-agent”.
To give a brief example (taken from their Github readme): if you were to write a test for a user endpoint and assert that simple get request returned a 200 and a JSON response, you could use the following:
The following examples are taken from what I have completed so far of the new Coffeestats API, they are written in TypeScript so you may notice some ES2015 features.
Submitting new coffee
As stated previously, in order to have the safety net of service tests in your API you would first make a contract of how the API is expected to behave and in this instance, the Coffeestats API needs to allow for the submission of new stats. It should respond with a 201 status code so that the web application knows the submission was successful, or with an error object to know if the submission was unsuccessful.
With that in mind, the first test was written to ensure that the `/stat` endpoint exists and it should return a 201 if a correctly formatted submission was provided:
Next, I wanted to ensure that the `/stat` endpoint returned an appropriate status code if an invalid stat had been submitted. I started by creating my test, which is shown below:
In these two brief examples, you can see that you can write tests in a structured manor that’s very familiar to unit testers, as we’re using the Mocha framework. If we were to compare these with a similar example written in Gherkin, we might have the following:
In summary, you can see that using `supertest` and `mocha` to create these service tests is more simple and more flexible in comparison to using Behat. Also as we’re running these tests in the Node engine they’re lightning fast in comparison and allow for a much faster feedback loop.
Outstanding problems I’ve yet to overcome
One of the main barriers I’ve yet to overcome is the priming of a database. It might be best to give an example of the problem, so here goes:
One of the Coffeestats endpoints is a simple ‘GET /coffees’ which can be filtered to just ‘get total coffees consumed today’ e.g. (today is 30-03-2016) `GET /api/coffees?date=30-03-2016`. Now, the problem is that in order to create the best test possible I should prime the database to have 2 coffees submitted today and then assert in my test that hitting the defined endpoint returns data which says that 2 coffees have been recorded today.
My initial hope was that I could effectively mock the MongoDB so I could define what should be returned from a query to the coffee collection, but this has proved tricky so far. If anyone has a pointers, or experience doing this please let me know in the comments!
As it stands it looks as if I’ll have to write a separate database provider in my tests so I can clear and insert the expected data before running the test.
Hopefully I’ve clarified what API service tests are and why they’re really useful, especially in a micro-services environment. I also hope I’ve demonstrated how you could implement your own NodeJS based API service tests by providing some practical examples from our Coffeestats project.