Automating Tests in Elixir Projects

I certainly agree that terminology can get quite muddling. While I’m comfortable using these terms in a more relaxed way, I appreciate your call for clarity - and I see that I haven’t always been as precise as I could be.

That said, I see things differently when it comes to the role of mocks in testing. You argue that mocks obscure what’s really happening, but I find that when tests cross boundaries (where “Domain A tests” get entangled with “Domain B” concerns), it is that very entanglement that can be a source of obscurity. In such cases, introducing mocks can help isolate those concerns, making tests more focused and systems easier to understand.

Moreover, I view adding testability as a natural part of iterative development.

But I share these thoughts not to convince you, but to marvel at the breadth of our testing tent and the diverse approaches we can embrace. There’s much nuance and many tradeoffs involved.

I’m thankful for these discussions, and the video and book references shared. They underline the nuance we can decide to embrace.

Also, I’ve updated my blog post to sharpen some of the language and findings, based on the exchanges in this thread. We won’t ever reach total peace on this topic - mocking always seems to bring out strong opinions - but I really do appreciate the perspectives. These conversations help clarify the tradeoffs, even if we land on different defaults.

I don’t think you understand what I’m saying.

That’s on me, so let’s try again.

If you need to change your implementation or internal code in your system to satisfy some perverse idea of test isolation. Then you’re in for a world of trouble.

If you’re working on systems that are interacting with the outside world, then it’s better to control that by using a database, webserver, file system and etc. to simulate the reality that your system is running in.

Don’t change your code. Just simulate the conditions your system will be running in.

I hope that is clear enough. And to be frank I don’t think you would disagree.

2 Likes

I actually do think we disagree somewhat — and that’s totally fine, it’s a good convo.

I’m not against changing internal systems to make them easier to test, as long as it aligns with simplifying the overall design.

That said, I’m all for functional cores, values as boundaries, and orchestrating shells — but I also accept the case for internal mocking. Gary Bernhardt gets away with “not testing the shell,” but I’ve had imperative orchestrators with enough logic to warrant their own tests. In those cases, I have seen value in mocking internal systems to focus on how the orchestrator handles edge cases — without spinning up and configuring full subsystem-domains.

To me, the foundation of testing is putting systems “under the microscope,” without being overwhelmed by unrelated concerns. This touches on the timeless “classist vs. mockist” debates, which ultimately come down to context: complexity, team dynamics, and other tradeoffs. The tension between those perspectives often pushes better design — which is why it’s such a classic topic.

To be clear, I’m not advocating for mocks everywhere (though I’ve probably sinned in that direction before), but I do see mocks as a valid tool in the toolbox — worth considering as part of the tradeoffs (even if just temporarily, until we land on a simpler, more robust design).

The testing space is wide. It has to be, to fit all of us :slight_smile:

Sadly this conversation seems to be going in circles.

It would be great if you could show an example project where mocking of internal logic can be applied and show pointers on its characteristics (even if that implementation were to be just temporary). That would certainly will solve this argument in a jiffy, as pointing to camps is not a compelling argument.

3 Likes

Simplifying the overall design is achieved quicker with strategical small refactorings that make the code easier to test. Like breaking apart big functions into smaller ones. Not via internal mocking.

An example would be much more convincing. With Elixir you can start up your entire app and its dependencies and start testing it very quickly.

I have a feeling you’re talking about some super heavy runtimes here, like Java and C#. But “spinning up and configuring full subsystem domains” I never found to be an issue in all my Elixir career (9 years). docker-compose works fine when you have dependencies outside the app itself.

Who’s getting overwhelmed by those? Sure, I had cases when setting up the test harness was laborious but (1) it was a one-time investment and (2) was still resulting in a clearer test suite and didn’t need mocks.

Only if we qualify that with “they’re a last resort, only when absolutely nothing else can possibly work”. If not, and if you keep insisting mocks are just as valuable as all other testing methodologies then I’m strongly disagreeing with you.

Honestly, this is boring and needlessly divisive, as I already said in a previous reply. Apparently you like your camps.

Show us some examples where mocking wins by a mile. If the core of your point is “well, we can either use mocks or not” then that’s not an interesting thing to say. It’s like saying that the sun is either visible or it’s not. Well, duh.

3 Likes

I genuinely don’t understand how we keep reverting to “camps.” We’ve already acknowledged that testing strategies exist along a spectrum of trade-offs, and in my last reply, I referenced the “classist vs. mockist” debate specifically to illustrate that spectrum — not to promote binary thinking.

It’s not controversial that some developers lean toward testing behaviors and avoiding implementation details, while others lean toward testing unit interactions and dependencies. There are nuanced trade-offs within those approaches, as I believe we’ve agreed.

And from that, it naturally follows that most developers will engage in some form of mocking, however infrequently. That’s why my blog post focuses specifically on the how of mocking.

While I respect the preferences being expressed here, I want to be clear: my involvement in this thread is focused on the technical mechanics of mocking. The “when” question is also valuable, but it deserves space to explore the trade-offs with care and depth. That’s blog post material — not something to untangle in a forum thread.

So, with respect, I’ll step away from this sub-topic. If mocking is still considered “only when absolutely nothing else can possibly work” even after multiple replies here have highlighted the nuance, then we likely see things quite differently. And that’s okay. I reject the position that pushes mocking to an extreme edge, just as others can reject mine. My focus here remains on how to mock — specifically to avoid this kind of circling.

1 Like

Apologies if I came off a bit abrasive. I felt the discussion was not going anywhere.

Of course we can civilly agree about the degree of usage of mocks.

But you are quite right that was not the topic. Sorry for derailing. Not going to pursue this (indeed irrelevant to your blog post) angle.