Live data from Hacker News

Why Most Unit Testing Is Waste [pdf]

rbcs-us.com

81–90 of 159 posts

Re: Why Most Unit Testing Is Waste [pdf]

#81
post #34

Earlier quoted context omitted.

Also, there's a followup by Coplien which has not been discussed: https://rbcs-us.com/documents/Segue.pdf So maybe this document should be the focus of the discussion now.

I'd love to submit this document to HN, so it has a chance to get a wider audience than provided by this sub thread. However, the title "Seque" is completely unspecific and hence totally useless. Given that title, I don't see how to submit this to HN in a way that it attracts readers. This is really a pity.

Submitted here https://news.ycombinator.com/item?id=15593322

Coming up with a title was indeed a bit difficult.

Re: Why Most Unit Testing Is Waste [pdf]

#82
post #79

Earlier quoted context omitted.

These are indeed useful strategies, but they do not invalidate the point I am making here. Fuzz testing is system-level testing, not unit tests, and so is along the lines Coplien is proposing (especially when combined with assertions in the code.) Invariant testing implies an invariant, i.e. an interface-level design contract, while the post I was replying to was predicated on systems where "the code is the spec", an…

OK, just to back up a step, here's my best argument in favor of automated testing: Virtually nobody just makes a change and ships it users without some kind of testing. Maybe you run your program by hand and mess around with the UI. Maybe you call the modified function from a listener with a few arguments. Maybe you have sadistic paid testers who spend 8 weeks hammering on each version before you print DVDs. (And tho…

No-one is arguing against automated testing - in fact, I have said elsewhere that I think test automation is the best single thing most development organizations could do to improve their process. In the article, Coplien says that his position is often mistaken for an attack on test automation, which it is not - and it is certainly not an argument against testing, either; it is an argument about how to test effectively.

What I am doing here is using the idea of automatic unit test generation to show that Coplien's argument cannot be dismissed with the claim that all unit testing adds value.

Re: Why Most Unit Testing Is Waste [pdf]

#84

Earlier quoted context omitted.

>That is, the only specification for how the system should work is how it worked yesterday. In that case, unit tests serve as a great specification. Unit tests are better than nothing, but integration tests usually serve as a better specification still. Unit tests are ok at specifying low level side-effect-less modules though.

Yes, and furthermore, due to the combinatorial explosion, and as explained in the article, unit tests can only cover an infinitesimal fraction of all the possibilities at that level. The sort of interfaced-based testing favored in the article ameliorates the problem because it uses the inherent abstractions of the code to prune the problem space. In addition, if you depend on unit tests, you cannot tell if a change h…

In my opinion, the way that most unit tests are written is mostly a waste of effort, but there are a class of unit tests that are much better suited to the task. The class of unit tests I'm referring to is property-based tests.

The most famous property-based testing framework is QuickCheck, but there are plenty of others, e.g. FsCheck for C#/F#, ScalaCheck for Scala, Hypothesis for Python, etc...

The general idea being that you write out a specification that the code should meet, and the test parameters are determined at runtime, rather than being hardcoded. There's more to it than that, but that's the general idea. If you want a simple introduction, I'd recommend this video:

https://www.youtube.com/watch?v=AfaNEebCDos

Re: Why Most Unit Testing Is Waste [pdf]

#85
post #76

Earlier quoted context omitted.

The article addresses your first point in a big section: 1.4 The Belief that Tests are Smarter than Code Telegraphs Latent Fear or a Bad Process Your other point about only good programmers not needing unit tests is moot as you haven't followed it through to the conclusion. Namely, if bad programmers write bad code that needs unit tests, they're also going to write bad unit tests that don't test the code correctly. S…

Tests don't have to be smarter than the code. They just have to be different code. They're screening tests, not diagnostic tests - if the test and the code disagree, you might have a problem. If they don't, then hopefully you don't.

Actually I’d argue tests should never be smart code.

It should be short, plain, simple and make it obvious what is being tested, how and why.

Because when that test fails you want to quickly understand what the problem is.

“Smart” (or just too big) tests all detract from this.

Re: Why Most Unit Testing Is Waste [pdf]

#86
post #8

I pretty much agree with all of this. Unit tests are great when you have a large code base with dozens of apps and need to modify a core library to remove side effects. How do you know you didn't break one of the apps? But if we go deeper, why does the core library have side effects? Because it was a crummy, poorly designed piece of crap to begin with. If it was originally written with high quality it wouldn't need t…

> I pretty much agree with all of this. It's easy to disagree with someone who portrays an enemy which doesn't exist. I disagree with this piece everywhere it manages to land somewhere concrete, where its claims can be verified and assessed. > But if we go deeper, why does the core library have side effects Let's not get ahead of ourselves in theoretical, non-applied functional programming. As even Haskellers recogni…

> In fact, we use computers for their "side-effects".

We use computers for their effects. "Side-effects" are things that happen by accident, or incidentally, when we were trying to do something else.

Re: Why Most Unit Testing Is Waste [pdf]

#87

Earlier quoted context omitted.

Funny thing. Unit tests force you to think about good code design. Integration tests don't. If you only have integration tests in your system, you'll most likely end up with a big ball of mud. I've seen this so many times in so many real world projects that it hurts.

> Funny thing. Unit tests force you to think about good code design. Integration tests don't. They absolutely do, but at higher levels of abstraction, in terms of interfaces, interactions, constraints, obligations and responsibilities. In fact, unit and integration tests make you think about design in essentially the same way.

Whatever floats your boat. My experience in large enterprise products is exactly the opposite, but I'm glad it works for you.

Re: Why Most Unit Testing Is Waste [pdf]

#88
post #54

Earlier quoted context omitted.

> Namely, if bad programmers write bad code that needs unit tests, they're also going to write bad unit tests that don't test the code correctly. So what's the point? Let's assume you hire good programmers, because otherwise you're doomed. But oftentimes, the "good" programmer and the "bad" programmer are the same person, six months apart: 1. John writes some good code, with good integration tests and good unit tests…

I appreciate your answer, but the destructiveness of the reward loop is directly addressed in the PDF. I also have no problems designing APIs, experience is what you need and the experience in asking the right questions. No amount of TDD will solve you getting half-way through a design and then finding you needed many-many because you misunderstood requirements. Other than that API design is (fairly) trivial. I spend…

> I appreciate your answer, but the destructiveness of the reward loop is directly addressed in the PDF.

I've gone back through most of the PDF, and I can't figure out what section you're referring to. There's a bunch of discussion of perverse incentives (mostly involved incompetent managers or painfully sloppy developers, who will fail with any methodology), but I don't see where the author addresses what I'm talking about.

Specifically, I'm talking about the hour-to-hour process of implementing complex features, and how tests can "lead" you through the implementation process. It's possible to ride that red-green-refactor loop for hours, deep in the zone. If a colleague interrupts me, no problem, I have a red test case waiting on my monitor as soon as I look back.

This "loop" is hard to teach, and it requires both skill and judgment. I've had mixed results teaching it to junior developers—some of them suddenly become massively productive, and others get lost writing reams of lousy tests. It certainly won't turn a terrible programmer into a good one.

If anything, the biggest drawback of this process is that it can suck me in for endless productive hours, keeping me going long after I should have taken a break. It's too much of a good thing. Sure, I've written some of the most beautiful and best-designed code in my life inside that loop. But I've also let it push me deep into "brain fry".

> No amount of TDD will solve you getting half-way through a design and then finding you needed many-many because you misunderstood requirements.

I've occasionally been lucky enough to work on projects where all the requirements could be known in advance. These tend to be either very short consulting projects, or things like "implement a compiler for language X."

But usually I work with startups and smaller companies. There's a constant process of discovery—nobody knows the right answer up front, because we have to invent it, in cooperation with paying customers. The idea that I can go ask a bunch of people what I need to build in 6 months, then spend weeks designing it, and months implementing it, is totally alien. We'd be out of business if it took us that long to try an idea for our customers.

It's possible to build good software under these conditions, with fairly clean code. But it takes skilled programmers with taste, competent management and a good process.

Testing (unit, integration, etc.) is a potentially useful part of that process, allowing you to adapt to changing requirements while minimizing regressions.

Re: Why Most Unit Testing Is Waste [pdf]

#89

Earlier quoted context omitted.

Refactoring code usually means you have to refractor unit tests as well, since they are so closely tied to the structure of the code. Integration tests, however, should not have to change, since they are typically run against the external interface to the software, which shouldn't change if you're just doing a refactoring.

Funny thing. Unit tests force you to think about good code design. Integration tests don't. If you only have integration tests in your system, you'll most likely end up with a big ball of mud. I've seen this so many times in so many real world projects that it hurts.

Except that in my experience, unit tests just end up being a big ball of mud too. And at that point, they don't make refactoring easier, they actually make it harder.

Having good integration tests means that you're free to completely re-organize your code, and you can still test that it works as expected.

Given that requirements change over time, even a well thought out code structure will likely need to be refactored at some point, and being able to have a test suite that doesn't have to be re-written during a refactoring is extremely valuable.

I've also seen code bases become unnecessarily complex because so much thought was put into how to unit test it, that not enough thought was put into writing clear, easy to understand code.

Re: Why Most Unit Testing Is Waste [pdf]

#90
post #4

I disagree: https://henrikwarne.com/2014/09/04/a-response-to-why-most-un...

There are a number of points here that I do not find convincing - for example:

The combinatorial complexity argument does apply more (much more, in many cases) to unit testing than to testing at higher level of abstractions, broadly for the same reasons that abstraction ameliorates the design-complexity problem. Consider a program using heuristic methods to find a near-optimal solution to an NP problem: not only would testing that it produces valid solutions at the program level be a lot simpler than unit-testing all its components, no amount of the latter would establish that any of its solutions are valid. The point is not that integration testing allows you to cover the whole state-space, but that it is a more effective way to select what you test.

The point of assertions is that they are tested in the execution of integration tests.

It has been my experience that most of the effort expended in the debug-fix cycle is a result of errors in decomposing the problem (or, equivalently, composing the units) - for example, an incorrect assumption about the data a unit uses, rather than the handling of the data in accordance with the assumptions made about it. Discrepancies between what is expected of a component and what it does also seem to be common, such as when one component is predicated on a constraint being respected by another, but the latter does not always do so.

Post reply on HN