Questions on Database mocking
My team is at this stage where we realize that more automation of testing into our processes is needed. Relying on the QA teams isn’t the best use of their resources and isn’t the most concrete/reliable approach for catching bugs in the system.
The QA team is starting to utilize Selenium IDE into their testing to automate some of their work. And the development teams are starting to incorporate some unit tests as well. We’re having an issue with that and this post is a (call for discussion/cry for help)
a bit of context here: The application is built in a micro service architecture that communicates through HTTP Requests. The API is currently is a thick layer (which we’re gradually thinning down and moving all the business logic and micro-services coordination down to the micro service layer itself.)
Now we’re starting to create unit tests at the micro services which are structured as follows: (I’m not discussing how the project should be structured here)
Application ├── routes/ │ ├── Gender.js │ └── User.js ├── libs/ │ ├── Gender.js │ └── User.js └── tests/ ├── routes/... └── libs/...
Essentially, the HTTP endpoints/the routes merely call the functions in the libs which in turns talks to the database through an ORM (
knex). Now as many great developers/articles/books suggest, we’re going to need to mock the database, so the unit tests are run in isolation of the database connectivity issues.
Now this all sounds great until I tell you this. One of the driving forces for adding unit tests to our codebase was a recent incident where we updated Knex’s version (to resolve some of the security vulnerability alerts). This resulted in some of the data being returned in an unexpected format (returning empty object instead of nulls or the other way - doesn’t matter) breaking our application. Now if I do mock the
Knex with a library such as
mock-knex, then I’d still not get the visibility of such issues when they happen again.
Our other approach is to create a containerized image of the database with enough test data to run our tests against. That way, we can test the units talking to the database. We can even tests the routes themselves with a library such as
supertest (making this more of integration test, really). But as you may guess, the routes are actually where most of the business logic would reside given that most of the function that would normally be unit tested are nothing more than just calls to the ORM/DB.
What we need to understand here is that the complexity of our routes will differ. Sometimes it’s just a matter of calling one function and returning its result as is. Other times, it will be sending requests to multiple functions and performing some kind of data manipulations, …etc.
Some comments from my research:
- “Don’t mock anything you don’t own!”
- Have an installation of the database that you can just delete and recreate a test database
- Or containerize the database.