This post is a short, generalized summary of the preceeding two. I believe those two posts put readers off due to their massive length and the fact that they were seemingly tied to Bazel and Java, thus failing to communicate the larger point I wanted to make. Let’s try to distill their key points here in a language- and project-agnostic manner.

My latest developer productivity thesis is that integration tests should be written in the exact same language as the thing they test. Specifically, not shell… and not even Python.

This pronouncement applies primarily to tests that verify infrastructure software like servers or command line tools. In these cases, it is too easy to fall into the trap of using a scripting language because it feels like the natural choice for interaction with the program. They are called “scripting” languages for a reason, after all.

But I argue that writing your tests in a language that is different from the rest of your project is a big mistake that will hurt the long-term health of your codebase, and once trapped, it’s almost-impossible to escape. Mind you, I’ve made this mistake in the past countless times and I’ve witnessed every other infrastructure team make the same mistake. I’ve also observed teams try to make a wiser choice by using Python instead of the shell, but the problems that eventually surface are the same. And I’ve always regretted these choices months or years down the road.

The core of my arguments is that you should stick to the language your team is familiar with. In most cases, your teammates are most experienced in the language used for the core of the project, and it’s fair to assume that they actively want to master their craft in that language. Therefore, introducing a second language for the integration tests will make them second class. This doesn’t help at all, especially when many developers still see writing tests as a chore—and you don’t want to add yet one more barrier to the already-cumbersome task of writing tests.

Additionally, and if you choose or chose the shell… keep in mind that most developers are not experts in this language. If forced to write code in it, they will inevitably put together functional code, yes, but code that fails to follow good programming practices and is riddled with subtle bugs (think: quoting bugs, expansion bugs, abuse of global variables, etc.). And no, it’s worthless to train your developers in an arcane language such as the shell: there are many more useful things for them to learn.

Lastly, by using the same language throughout your project, you will avoid having to context-switch between coding your actual application and its tests, and you will also be able to use the same IDE and potentially reuse the same libraries. This reduces the feeling that tests are an after-thought and can help in increasing their quality.

Granted: depending on the language you are using, sticking to this proposal this will mean significant more work upfront to lay out the foundations for your tests. But trust me: this work pays off. You may also imagine that the tests will be more verbose than if they were in shell, but that needn’t be the case. It’s really up to you to define the right level of abstraction to keep the tests succinct, and there are some well-established testing practices out there that you should follow.

If this sounds interesting, read the series: