Mocking external data sources

Hi everyone. I’m struggling with unit testing my microservice that gets data from a database.
I would like to mock the function that returns the retrieved data. On SO Stack overflow on focking they suggest injecting the function as argument.

I am wondering whether this is a good practice. Is it nice to adjust the code you want to run in production just so you can test it? Currently my code does not need any setter or parameter to execute the function, and it seems to me that injecting this function just to test it is not really a nice way to test the code.

This is just a small code snippet (with some things left out) that shows what i want to achieve:

func testMe() {
    conn := getBackOfficeDBConnection()
    deviceInformationSlice := fetchDeviceInformation(conn)
    nodeSlice := fetchNodeReports(conn)
    lastNodeStatus := fetchLastNodeStatus(conn)

    newNodeStatuses, statusEvents := detectStatusChange(nodeSlice, lastNodeStatus, deviceInformationSlice)
}

I want to test the function “testMe”, where I am in control of the data that is given by the fetch* functions.
How do I achieve this?

Have you considered running tests like this against a real db with test data? Then you wouldn’t need to mock.

Personally I unit test functions which are isolated (mostly models and libraries) and run integration tests on the rest which call the unit tested functions and fetch external data (mostly handlers). It’s fast and more importantly tests against the real conditions in production and gives you a full stack test.

This translates to unit tests on functions like detectStatusChange (where your logic is), and integration tests against a test db for functions like testme.

Yes I have considered and it might be a good idea after all… Do you have some sort of Docker environment set up for this?

You could use docker but it’s not necessary. You could either:

  • Set up the db locally on your dev machine and use it
  • Use a remote db for testing (obviously not one on your production machine).
  • Use docker containers - if you had a complex setup with lots of data sources or had many employees, containers might be a better option, but if you need it, you’ll probably know.

I just set the database server up once on my dev machine every few years and then use it for all projects running locally (I use Postgresql) for quick tests while developing. I usually have a staging environment too (same hardware as production), and use CI to run tests as well separately, there are lots of options.

What you do have to do as an extra step is set up your getBackOfficeDBConnection to use a test db rather than the dev or prod at the start of each set of tests, and clear the db (or insert mock data). All that takes is one function though which uses test credentials rather than dev or production. IMO this is simpler than maintaining a whole mock data layer which inevitably diverges from the real db in behaviour.

2 Likes

Thanks for your feedback. I think I will run a local database with my testdata, i already have a way of supporting multiple db endpoints (One for dev and one for production) so that won’t be too much of a hassle.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.