back
4 comments
My opinion on methodologies is that if it is too often misunderstood, then it is wrong.

The entire point of giving a methodology a name and writing about it is to get everyone on the same page. So if people have different ideas on what TDD is, then people should stop talking about TDD until everyone agree what is and what is not TDD.

And only after everyone agrees, one should talk about the pros and cons and assess the success of the methodology depending on the situation. "you are doing it wrong" is not helpful.

Back to the article. I think not mentioning TDD at all would make it a better article.

I've had this problem with team vocabulary. Once one word gets used to describe 2 or more things it becomes impossible to roll back.

I tried banning a particular word once and coming up with 6 new words on the basis that you couldnt tell which of the 6 meanings somebody was using unless you used a different term for each one. That didnt work very well. People got too attached to the old, overloaded term.

Expecting an entire industry to stop using a term theyve become used to is not realistic.

Talking about it is how we figure out what to agree on.
TDD cultists are awful about that, none of them do TDD the same way and if you don’t like TDD it’s because you’re wrong and are certainly doing TDD wrong.

I wrote a short rant about it last week: https://dev.to/thiht/tdd-is-a-personal-practice-3o76

They will all be misunderstood, unless the title is the manifesto. But since the title needs to be short, it won't be.

Another example: Nation State. I can't get a clear answer to what that really means :-).

Back to computers: REST is a great example.

The entire point of giving a methodology a name is making money off it as a tech influencer slash management consultant. Those people don't care one iota about whether everyone agrees or not.
The biggest missing element, in my mind, of the pro-"classicist" and anti-"mockist" view is that the practice of writing unit tests with mocking leads to refactoring your code until it works with that approach, which in turn leads to better-designed code. I don't like the emphasis of "yeah but refactoring code leads to needing to rewrite mocked tests", because if you've designed your code well, then the need to adjust an api boundary should be less frequent than the need to adjust the internal implementation details. Focusing on integration tests means you can get away with poorly designed code full of corner cases that your integration tests can't catch. Besides, "we can keep the fast feedback loop with parallel tests" really increases the demands on complicated tooling that breaks often.
You can only get away with poorly designed code if that's not caught in the code review. I'd argue that while that might be a nice side benefit of some testing practices, forcing you to rewrite your code isn't relevant to the test - in fact the opposite! Your tests should work irrespective of your code's internals!

(Also, you can easily run integration tests in parallel with a little planning and attention to detail. For example, if your IDs don't rely on a sequence (like UUIDs), you can generally run them in parallel regardless of database connections.)

> forcing you to rewrite your code isn't relevant to the test - in fact the opposite! Your tests should work irrespective of your code's internals!

Are you avoiding rewriting your code so you can write integration tests, or are you writing integration tests so you can avoid rewriting your code?

Those that have been around the block of refactoring code so you can write good unit tests, tend to realize that the better-designed code isn't a side benefit. It's the entire point. The test is the side benefit.

Integration tests should be avoided if the same coverage can be reached with a refactor and some unit tests. For instance, it's very common for components to rely on complicated combinations of state. For instance, imagine a nightmare component that has nine boolean state parameters. To integration-test every combination, that's 512 cases. But in cases like those, you might discover through refactoring that some of those state combinations can compressed. For instance, you might be able to refactor into three sub-components, each of which take three boolean parameters and return one boolean result, and where the parent component only depends on those three booleans, which can be mocked. So then in that case, you've reduced the amount of tests you need to write to 32 total... that's 1/16th the effort.

I mean, I know that in common practice, neither are done, and people just leave the component largely untested, and then get bug reports that they close as "Can't reproduce".

Thanks for the heads up. It’s 10 years old, but I hadn’t seen “Mockists Are Dead. Long Live Classicists.” before (https://www.thoughtworks.com/insights/blog/mockists-are-dead...).

The Classicist point of view resonates strongly with me - I’ve long considered mocking in tests to be a code smell, and only usually justified for stubbing external services or hardware.

> Now, you change a little thing in your code base, and the only thing the testing suite tells you is that you will be busy the rest of the day rewriting false positive test cases.

Never happened to me, and we use a lot of junit tests at work.

I don't see the value in "Do not isolate code". Isolating a single method or such is often necessary, especially a unit test of a Utils class. But I only tend to do this if the "user story" centric test cases don't end up covering everything.

This is pretty good and much of it resonates with my recent thinking on testing (I seem to revisit this topic every few years and rethink testing in general). I appreciate that it's pragmatic and not dogmatic. There's a lot of "tradition" in testing that has kind of built up over the years and not a lot of questioning the assumptions. Thanks for sharing.