Co-locate Your Unit Tests
Put Your Stuff Together
It’s a new year, so it’s time to do some new year’s resolutions. Mine is to colocate my unit tests!
It’s not something like “Clean”my code, as if it’s something to be scrubbed. But it is something about Developer Experience, or DX.
Put your Unit Tests right next to the thing they test. There’s no better way to do it
This should be uncontroversial, but I’ve found some engineers who want to do weird things like separate tests into a test folder, a different repository, or otherwise organize tests in a way that keeps them separated from the code. Whether it’s for “oragnization,” or to keep the code “clean,” it’s crap.
Why You Should Put Tests Close to their Subject
I think the case for co-locating tests is pretty clear but I’ll try to lay out my reasons.
Ease of Navigation
Say you’re working on a piece of code, and you break a test. Where do you go to fix that test if you’re actually causing such a breaking change?
If your tests are co-located, it’s right there; it’s the same file you’re working on plus test
or spec
or whatever. It’s so simple, it feels silly pointing it out!
It’s also easy to figure out where a unit test should go: the name is already given to you, and you know where it should go. There’s no decision to make, and that’s one of the best places to be as a programmer. I’ll probably write about this
Shorter Imports
If you have an import system that doesn’t require you to path troll, or navigate up and down different folder structures, then you probably won’t care. But we who work on JavaScript often need to do ..\..\YourStuff\Component
to get code.
If you’re not co-locating your tests, then each of your tests needs to do that to get to the thing it’s working on! Rather than just ComponentToTest
, you’re going from wherever you are in the tests all the way down to your component.
It’s Easy to Know if Something Has Any Tests
Lots of us work with what I’ll call sidetrays. VS Code has one, and lots of Emacs and Vim configs hold one. If you’re working with co-located tests you can actually see which files have corresponding files that are next to their corresponding components. If you’re using a nice file tray it’ll even add an easy-to-parse icon.
I know this can get cluttered but if you’re using a really really nice file tray then you can filter by file type, so you could look at only tests, or no tests.
If you don’t have this and use the tray a lot, you’re missing out.
Why Putting Your Unit Tests Somewhere Else Sucks, and Your Opinion Is Wrong
I’ve been told excuses as to why you’d split your test files. But I actually found some arguments
Stack Overflow Guy
here’s a quote from StackOverflow, where we suggest splitting all tests into a test directory.
My personal recommendation is to go with #1. The reasons are:
Your source code is not ‘polluted’ with code that is not related to actual business logic. Mind that it is not so uncommon to have more than one test file for the same class/module. There are more that just unit tests you are probably going to write. What about e2e? Are they going to be placed along side corresponding ‘something’, as they are not so bound to the particular file? So you risk end up cluttering your tests over whole project - some of them in one place and some in other. Separation of all tests in the dedicated directory - solves this issue. Its easy to prepare the deploy of the project. Otherwise you will have to somehow strip out all tests from the transpiled sources. Do not trust me on this - have a look at the established projects like React and Angular 2
This is terrible advice.
“Polluting your code”
Your source code is not ‘polluted’ with code that is not related to actual business logic. Mind that it is not so uncommon to have more than one test file for the same class/module.
What does this even mean? How can a codebase be polluted, and what is the unpolluted state?
Doesn’t doing this guy’s terrible breakdown cause it to be “disjointed,” or “fractured,” or “malintented”?
The problem with zealots like this is they’ll add undefinable adjectives regarding code. See the Hack Robert Martin on “Clean Code.” If you still think “Clean Code” is “better”, I have a bridge to sell you.
You’re not “polluting” you’re code, like it’s some oil spill or something. You’re putting things that talk about the same thing close together. Code isn’t some park, or the air, or a dumpster. I mean it could be, but this descriptor is entirely unhelpful.
Here’s an allegory:
Do you group your books by topic, or do you alphabetize by title, or do you put all the blue books together?
The answer is: it depends. Any of these organizations could be valid, but I’d guess most people would group books that they read together by topic, because it makes it easier to reference books that talk about the same thing together. But if you wanted you could put them together by color if you wanted the bookshelf to look a certain way.
This argument to split your code is to me splitting your books by color. It might look nice, but I’m not certain it’d be easy to find a book about cooking, vs a book about gardening.
This person might work on a bifurcated team: QA or testers work on their code and Developers work on their code. In that system, the suggestion is great, but consider if such an environment is more desireable. I don’t have the answer, but I have an opinion.
Finally, the point about multiple files pointing to one component. So what? I think this guy has a bad IDE, but this seems like a non-problem.
What about e2e?
There are more that just unit tests you are probably going to write. What about e2e? Are they going to be placed along side corresponding ‘something’, as they are not so bound to the particular file? So you risk end up cluttering your tests over whole project - some of them in one place and some in other. Separation of all tests in the dedicated directory - solves this issue.
This argument sucks because it’s a composition fallacy; this person’s argument is that because it’s hard to put end-to-end tests next to their subject then we should just throw the baby out with the bath water and do the same with Unit Testing.
I think you should put your e2e, or integration tests in their own test folder. So, we don’t disagree about that. But this guy would say that you had to buy a new car if you got a flat tire - after all you get new tires with a new car anyway right?
Do create a testing directory for your tricky tests like integration or e2e. Do colocate your Unit tests.
But my Deployment
Its easy to prepare the deploy of the project. Otherwise you will have to somehow strip out all tests from the transpiled sources.
This is probably the best argument this guy has, but if you’re shipping test code then you have a bad build system. Maybe when they answered in 2017 this was always the case. But if he was a good developer I doubt this would be a problem.
Today, most build systems discriminate against test code automatically. Sounds like a skill issue.
Assert Authority: Microsoft did it too
Do not trust me on this - have a look at the established projects like React and Angular 2
This is technically correct! Great job.
Are you building the next React or Angular? No? Oh, then it seems like this advice sucks. (if you are, then you probably have the foresight to actually fix this and my advice might not apply)
It’s Too Much - There’s too Many of Them
I swear it’s always, “There’d be too many files.” Like we don’t have the tools to filter down our projects, or we’re using bad IDE’s like Visual Studio. Look, shuffling papers on your desk doesn’t make you more productive, so pushing everything away from where you’re working just adds space for you to lose flow.
Look, I get that looking at a lot of files is a bit daunting. But pushing part of the problem away
The Bounds Of My Argument
Integration and larger, inter-component tests
Maybe if your code is so big you couldn’t actually test it using these unit test methods