Hacker News new | ask | show | jobs
by hinkley 2344 days ago
I believe Michael Feathers was just started a Twitter thread yesterday that talked, among other things, about moving IO to the edges of your code.

If you can divide acquisition from usage, I wonder how much less effort you need to put into API mocking.

Ages ago and shortly after I started testing, was the last time I had to do any low-level HTTP response processing. My coworkers could not fathom why I had divided the parsing and networking code into completely separate sections. Then I showed them how stupid-simple most of the tests were, instead of the convoluted mess of integration tests I'd walked into.

Hand the payload to I/O-free code immediately. You've done the hardest part at this point. Mocking out the network layer in any of half a dozen ways is a cakewalk in comparison.

3 comments

Yes! Yes! Yes! I've been preaching this approach ever since watching Gary Bernhardt's talk on "Boundaries" [1].

Splitting conditional logic from dependencies makes code so much easier to test. If you can do that, there's no need to mock anything. You can just pass simple data objects into your conditional logic for testing, and use a handful of integration tests to validate the end-to-end flow.

[1] https://www.destroyallsoftware.com/talks/boundaries

Bertrand Meyer talked a similar strategy. I believe he called them decisions and actions. There's a lot of requirements tied up in decisions.

With the exception of callbacks (and async solves that for single-issue scenarios), arguments don't need to be mocked. They're just arguments.

I believe this is similar to [Uncle's Bob clean architecture theory](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-a...) where you split the infrastructure from the business logic. Also similar to the repository pattern. In general, you are able to achieve loose coupling between your modules and thus better unit testing.

But being able to go down to the HTTP level and mock responses there provides a different benefit. You are able to do end to end tests but isolated to your own service. I always do that (alongside unit tests) so I can even catch errors outside of my code base, i.e. in my dependencies.

Yes, Cycle.js [1] taught me that lesson and it's been useful ever since.

[1] https://cycle.js.org/