Why Most Unit Testing Is Waste (2014) [pdf]
wikileaks.org
wikileaks.org
And that's how you get regressions. I get the rationale that these tests cover code which probably never changes, and tests are most useful for code that changes a lot. But if the guy who wrote the code left the company a year ago and then you have to change this code... it's going to be a lot easier if there are good tests.
(Yes, apps and frameworks based on a statically type-checked language would catch some of these cases. But not the ones that change behavior of something while leaving the relevant type signatures intact.)
I've certainly felt what he pointed out about tests becoming a real hassle to maintain while not necessarily being very valuable to keep.
took me 20 years to notice this.
This made me giggle. It's like magic. don't write tests, don't find bugs....
1. Unit tests only work in "functional" code composed of easy-to-reason-about components that support other similar components. The OO storm introduced a style of code which is impossible to inspect unless it is running.
2. Because Turing machines you need as many bits of test code as bits of real code.
3. Code coverage requirements can only lead to tests for their own sake, i.e. wasted lines of code.
4. If there are many more lines of tests than production code, your developers are quite possibly paranoid about what they're writing, and that's bad.
5. Tests that have not failed in a long time don't convey information, they only provide noise. Optimize your test suite to provide information.
6. The reward of seeing a green bar in an IDE encourages appeasing the test gods instead of designing a good system.
7. Assertions are better than tests.
8. The Agile culture has turned unit tests into something worse than what they could be without it.
Then when assertions fail, you write a regression test. But a unit test that verifies of the contract itself is verified correctly is needed too. More than once such a test actually found that it can be violated under common conditions or does not check what you thought of does. That is the main reason for "unit" tests.
It is even more required for multithreaded or parallel programming.
One thing I've noticed is that there really is more than one way to skin a cat. Some people like to have a more linear style in their code. I've found that such people tend to have good memories and considerable ability at reasoning. They can see a fairly large piece of code and see quickly where the errors are. They can remember that one piece of code on the other side of the project did something one way and code on this side of the project does it another way.
These people will often look at my code and it looks disjointed to them. They can't read the code and get a sense of what it is doing. They find themselves jumping around through hundreds of files just to figure out what's going on. If I have any ability at all it's really much more in the spatial relations side. I can visualise networks easily and reason about them.
I can never remember the details about how things are implemented and I'm a very slow reader (I'm dyslexic). I depend on trust. I want to be able to see a function and tell in 5 seconds whether or not it is correct. I then rely on tests to tell me when I have violated some assumptions somewhere -- because I don't bother to learn and have no capacity for remembering all the assumptions in the system.
Unit tests and the intense factoring that occurs when doing TDD (at least in a non-mocking style) favours a style where you admit imperfect knowledge about the system. It then gives you a framework for reasoning about the system. People (even on my team) are often surprised that I haven't used a debugger for at least 10-15 years. Tests are really a misnomer -- they don't verify the correct execution of the code. What they do is probe the execution of the code. It tells me what the code is actually doing and documents my assumptions about what it should be doing. If there is an error, there will be a mismatch in the two. I may or may not have an explicit test that fails during that mismatch, but I should be able to reason about it effectively.
It's a different way to think and a different way to work. IMHO, I think it requires considerably less mental capacity to work in a TDD way. However, on the other side of the coin it requires considerably more training/experience to do well. You definitely want to decide upfront which way your team wants to operate, but I'm not about to say that you're "wrong" if you pick a different approach than I would.
Anyway, thanks for doing the summary! It was very evocative for me :-)
I'd add that unit tests (above the method level) help to "tell the story" of the code. Coming into a large code base with well-factored code can be daunting, it's a boon to be able to step through unit tests that exercise even just typical scenarios.
Very well said.
Now, if your object architecture is "throw everything into one object", then OO can make it harder to test (or do anything else). But even on a very large class (5000+ lines - I know, I don't like that it's that big, but it's really hard to break up), I've used unit tests very successfully.
It makes a lot of sense to do broad smoke tests and full-cycle specific behavior tests integrating such strongly dynamically dependent subsystems, than to try to create all this artificial test harnessing and fake objects/servers/connections in order to attempt to isolate testing into object-level "units".
You just accurately described half of the Intelligence world accurately