Comment by switch007

3 years ago

On a tangent…

I’m currently losing the will to live with integration tests for an http service I’m writing.

It calls out to other services (often 3 or 4 external api calls for each of my http resources, each with complex data structures).

(I just want the external API data in a database!)

Tests are a pain because of the matrix of fixtures needed. My API endpoints behave very differently based on the attributes of the objects in the response from the other APIs. So I have lots of somewhat complex code to generate fixture data, which again is another source of error and a whole lot of code.

For one of my endpoints, I have to mock 1-6 API calls, multiplied by 3 or 4 variations of the returned data. It’s torture.

None of my tests are that obvious what it’s testing because the fixture code and json assertions are so big and long. We aren’t using an http mocking lib right now (eg wiremock) but I’m wondering if it’s worth it.

I guess a lot of it is because the APIs I’m calling are so badly designed.

Seeing as how you prob can’t consolidate apis to a single process for more control.

Seriously, having an http mocking tool is so helpful. I use msw, a node equivalent of wiremock. To help with a situation like yours, it’s easy to say “before this executes, I want the mock tool to return this response”. The abstractions are good enough that I don’t have to deal with recreating my dep-injected service objects, and really reduces the tests’ lines of code. It also seems like the most complex bit here is handling your permutations of code paths, as well as their error paths. I salute. I can’t think of a way to simplify it all except to be glad I work on smaller products now that don’t require so many microservices or 3rd party apis.

The unfortunate bit is ensuring your mock stays up to date with their api. But if we have most or all of the variations, then it’s their fault for breaking their APIs on us, no?

I think it probably IS the APIs that are a problem but since you usually cannot instantly get rid of such things I think you need tricks.

e.g. keeping your fixtures in separate files and naming them in such a way that the actual data doesn't appear in your test code.

You might use some fixture as a base value (in my case I had this problem with a big old structure that describes PKI certificates of may types) and have derived fixtures that are (the base plus a change to the "account" field or the base with the "accept" field set to "false"). I did this with python classes and inheritance. Each derived class copied the base class's data and applied a diff. YMMV but I mention it just in case it helps.

If these are all named and kept in separate files then your actual integration tests can look a bit simpler perhaps?

> I guess a lot of it is because the APIs I’m calling are so badly designed.

Sort of, sounds like the problem is that you have a distributed monolith. If things are this tightly coupled they should just live in same process. If you even had just a regular monolith (which I don't recommend but it is much better than distributed monolith) you wouldn't have this particular problem. Of course another alternative is to redesign the system so that services are based on independent domain capabilities so that they have high cohesion and loose coupling.