Welcome to MSDN Blogs Sign in | Join | Help
It's OK Not to Write Unit Tests

Don't feel bad, it's okay not to write unit tests.

But Unit Tests Work For Me!

First, are you sure you're really unit testing? Unit testing is all about testing “units”—independent pieces of logic. According to Michael Feathers, a real unit test cannot talk to a database, communicate across the network, touch the filesystem, run concurrently with another test, or require extensive setup. If they are any dependencies, they are mocked away. Do your tests do that?

That's what I thought. They're not unit tests, they're just tests.

But okay, who cares if you follow all the rules, at least you write tests. You probably work on a project that lends itself to easy testing, and your platform likely has great tools for the job. You also have great intuitions where the right level of testing is—or if not, you're at least at that stage in your career where you make lots of little mistakes and the tests you write actually help you catch them.

Realize, however, that not everyone has that same context as you. 

College students, for some reason, seem especially enthusiastic about unit testing. Maybe it's that unit testing was that teaching tool that got them from unconscious incompetence to conscious incompetence all the way up to conscious competence. For some, this experience can be the start of a love affair that lasts many years into their adult career. No one forgets their first crush. 

But once somewhere around level four of the Dreyfus model of skill acquisition, unit tests start to lose their effectiveness.  In fact, they might even be what's holding you back from further growth.

Training wheels are a best practice—for learning how to ride a bicycle. They're not a best practice for riding the tour de France.

Unit Tests Give Me Confidence When Refactoring! 

Yeah, right. Let's be real now.

There's this theory out there that Agile projects can refactor fearlessly because there's this immaculate suite of tests that can sound the alarm the second the smallest regression gets introduced. But anyone who's actually tried it knows that it's mostly just a fantasy. Unit tests tend to overspecify behavior—they test implementation details that don't matter, rather than fixed contracts that do.

And they're too fine-grained. The larger component may preserve its behavior (or not), but the comprising sub-units will be radically transformed. Many of them will not even survive the process at all. That's what refactoring means. I've never known a significant refactoring which didn't require the tests to be majorly reworked or even rewritten.

A test that needs to be updated every time the product changes is not really a test at all. Think about it.

Unit Tests Catch Bugs!

Really? When was the last time?

Let's be honest. Your tests mostly follow the “happy path”. Sure, on occasion you remember to test “the failure case”—the caller passed in null or a negative integer as an argument—mostly because you just got done writing that check and wouldn't it be a waste not to write a test to show how clever you were? Never mind that null or a negative argument is an assertable precondition that could never happen in production anyways. 

If you're a Java programmer and want to have a rude awakening, go download Jester. Jester is an automated mutation testing tool—it goes in and replaces “<=” with “<”, “&&” with “||”, “!” with whitespace. And then it re-runs the tests. And then you get to watch in horror as your tests still all pass, regardless of what the product code actually does.

It's also not uncommon for the tests to have the same bugs as the product. And why not? The same person wrote both. If the programmer writes code to give a discount to all orders above $1,000, when he writes the test is he going to double-check the spec to find out that the threshold is really $10,000? This is the so-called “ugly mirror” problem, where the code looks just like the code it supposedly tests.

Unit testing is no substitute for adversarial testing.

There are so many kinds of failures unit testing can't find for you. Memory leaks. Intermittent issues. Stress failures. Unexpected behavior in third-party components. Subtle interactions between features. Usability issues.

Code you forgot to write.

Yes, unit tests can only catch problems in the small—and the majority of your bugs are bigger than that, aren't they?

Unit Tests Improve My Design! 

No, they don't. If anything, unit testing encourages some pretty questionable practices, like making private methods public just for so they can get the code under test, or creating zillions of interfaces for mocking purposes, interfaces that leak implementation details like water leaks through a sieve.

Unit testing isn't all horrible, of course. For one, it's big on writing clean function and object contracts, which is a good thing. Its heart is in the right place when it comes to its rabid stance on decoupling—although a more sober analysis on sources and causes of design change is usually more helpful.

But there's a lot of things unit tests don't teach. You'd never get to Tell Don't Ask with unit tests alone—in fact a great number of tests involve introspection of state, often in encapsulation-breaking ways. Many unit testers are just fine with deriving Circle from Ellipse as long as they thoroughly test the arbitrary, idiosyncratic way Circle handles the case where you set unequal major and minor axes. And who cares about Open Closed Principle as long as the tests still pass after you make an invasive change?

At best, unit testing is a weathered signpost saying “good design practices are somewhere over there”. But it's no substitute for actually knowing those practices. 

Have you ever watched someone try to solve even a moderately complex problem with TDD alone? It's painfulReally, really, really, really, really painful. Maybe it can be done, but it really just amounts to a random walk across the problem space, and you'll have to stub your toe a good many times before you finally get to where you want to go. To make any reasonable progress, you already need to know a little something about good design principles from the outset. 

Yes, unit testing is just a signpost—and not a very good one either. Many are beginning to discover that functional programming teaches far better design principles than unit testing ever will. Academic esoterica like currying and monads and the lambda calculus aside, it's shocking the number of code construction bugs which relate somehow towards mutable state—which is what functional programming teaches you to avoid.

Strangely enough, functional programs often turn out to easily testable anyways, even when no deliberate effort has been spent to make them so.

If You Can't Test It, You Can't Ship It!

Unit testing is not the only sort of testing out there. Don't make the assumption that if a product isn't unit tested, then it's not tested at all. 

Testing is an economic activity like any other. Every minute spent writing tests is a minute not doing something else. There's always another test that can be written, and if you had infinite time you would write them all. But you don't. Somewhere out there is a point of diminishing returns. There's a point where you say, “we're confident enough; let's ship”.

Now I'll give you that some tests pay for themselves. Some of them are so good they even pay a never-ending stream of dividends. But then again, tests can have negative ROI. Not only do they cost a lot to write, they're fragile, they're always broken, they get in the way of your refactoring, they're always having you chase down bogus failures, and the only way to get anything done is to ignore them. 

Don't be suckered by the trite dictum that “no test is worse than having no tests”.

But It's The Corporate Standard!

Then your organization is dysfunctional. 

Sorry to be so blunt, but there it is. If it's any consolation, a lot of organizations have the same dysfunction: they don't trust their employees to do the thinking. They think they know better than you, and they don't.

Have you ever worked with a good manager? They're full of ideas. They'll suggest, they'll coach, they'll recommend. They'll cajole and beg and plead if they have to. But they won't tell you how to do your job, not unless it's a real emergency, anyways. They hired you, they gave you a task they know you can handle, and they trust you to make the details happen.

Good organizations know there are no best practices that apply regardless of context. They also know that every employee has a unique working style, many of them equally valid, and so practices that work well for one person or one group may not work as well with the next. Particularly enlightened organizations know that many so-called “best” practices are really just a gang of superstitions and prejudices in disguise. What else could account for the prevalence of thoroughly-discredited Waterfall methods in this day and age? It's a short walk from “the only practice we know” to “the best practice, period”, and before you know it, you've blinded an entire organization to better ways of doing things.

It's a wonder how any innovation occurs in such companies—but if it happens, you can be sure it happens by treasonously unconventional means.

So What Are You Saying, Man?

Don't get me wrong. I'm not saying that all unit tests are worthless, nor that you should never write one ever again. But I am suggesting that you take a good hard look at the time you're spending and ask yourself what benefit you are really deriving.

What I'm saying is that it's okay if you don't write unit tests for everything. You probably have already suspected this for a long time, but now you know. I don't want you to feel guilty about it any more.

There are so many other ways you can find bugs with less effort. Like asserts, to pick a random example. Maybe you already write a lot of them—but do you really leverage them? Or do you instead routinely ignore them like so many others do? If the latter, don't worry—you're probably not using them as effectively as you could. Just remember that if an assert goes off, it means you need to fix something. Don't write asserts to “notify” you of interesting events which your code already handles correctly. Assert is not a logging mechanism.

Acceptance tests are great too. Like, let's say I was writing a SHA-1 hash implementation. That's a lot of code. And I wouldn't write little tests all the way down.  But I would have a few tests validating that it works at a very high level, absolutely.

Agile dogma says that tests should be fine grained, but really, what's the point? Debugging is easy, at least in comparison to writing all those tedious tests. If you think about it, all you really need is something that alerts you that something, somewhere, has gone wrong—a “tripwire” test, so to speak.

Test what can fail. Test stuff that's easy to test. But don't beat yourself up trying to get 100% code coverage. 100% code coverage doesn't mean all that much, anyhow. 

Hope this helps,
- cashto

Posted: Tuesday, March 31, 2009 6:01 AM by cashto

Comments

James W. Shumaker said:

Several valid points, at the end of the day the results are what matter:

I have a two year old project that causes me nothing but pain and suffering, we've killed a great business opportunity by making a stagnant, behemoth of a code base that no one understands. -> I didn't unit test.

I have a 9 month old project that has ZERO (read that again) ZERO issues, has been working perfectly in production. The only problem is that it's for a client I love to work with and they don't need me to do anything, because it works. -> I maintained 100% code coverage throughout everything except the UI and DB layer, with appropriate mocking.

Unit testing drives my design & development. I have a perfect indication when to break things down. I have a perfect indication when things are doing too much. When the unit tests get painful, they tell me to stop wasting my time trying to force them to work and refactor the code.

When I refactor, I know absolutely that nothing is broken, not just because all the tests are green, but because my design that the tests drove emphasis solid and is less bug prone by nature.

I've also noticed that 9 times out of 10 my code works the first time I deploy it. Personally, that's a first for me.

The second I stop unit testing the quality of my code drops every single time without fail. Honestly, I can think of no single better way to force you to learn good design principles then testing. Period.

# November 4, 2009 11:57 AM

Nemanja Trifunovic said:

James, how can you even refactor without rewriting a whole bunch of unit tests?

# November 4, 2009 12:10 PM

Graham said:

I thought I was a big proponent of Unit Testing, but it turns out that I am writing unit tests for individual functions (no mutable state => very easy to test), and acceptance tests for behaviour of the whole application plus a few important classes.

The acceptance tests are what really allow me to  refactor, because they depend on the highest-level APIs, so I can rearrange all the code underneath and run-fix-run until the acceptance tests pass again.

Meanwhile the tests of individual functions keep working all along, modulo updating references.

# November 4, 2009 12:22 PM

James W. Shumaker said:

Graham, acceptance tests are absolutely necessary and I find them quite useful. They are good for verifying functionality and UI problems. They are not useful for driving code quality because it glosses over your entire middle tier (which is why you can refactor without breaking it).

Nemanja, I can refactor without rewriting a bunch of unit tests because the tests drove me to a design that only has one responsibility. Additionally, because I go to interfaces and not specific implementations (insert soldering lamp to socket example here) I can write new functionality without ever having to touch existing functionality (closed for modification, open for extension).

When you have to rewrite huge swaths of tests, it's because the code is not testable (big debate on that word, won't bring it up here). Simply put, if you keep your test setup's simple, it means your code most likely is smaller, easier to maintain, and only changes when one thing changes.

One example is I can wildly change my caching algorithm for part number generation by building a new service and wiring it into the IOC, without ever touching existing code. Additionally, if I get disgusted with one ugly piece of code (there is always at least one), I can go back and refactor it because the crappy piece was isolated from the rest of the system. I've completely rewritten a section of crappy code and broke it out into three services without ever having to modify the calling code.

Honestly, it's painful when you first (as in I spent 6 months or longer before the aha moment hit) start testing, once you stop fighting it and do what the tests are telling you, it's really quite beautiful.

It makes complicated systems boring, which is awesome.

# November 4, 2009 1:22 PM

Nemanja Trifunovic said:

James, one example: you apply extract method refactoring: http://www.refactoring.com/catalog/extractMethod.html

How is it possible you don't break your unit tests by doing that, unless they are not really unit tests but functional/acceptance tests?

# November 4, 2009 1:38 PM

James W. Shumaker said:

Those are private members. I would have most likely wrapped up my external dependency (The console in this case) in a service with an interface. The service would have a method println.

My tests for the target would be to call the Main() function on the class, or whatever it was, after I injected my console service through it's constructor. I'd mock the console and assertwascalled println with the argument being the line I expected to be printed.

Each assert would be a separate test in my class WhenPrintingOwing

ShouldPrintName

ShouldPrintAmount

Since the refactoring in this example happened with private helper functions within the target class, none of the tests would have been affected.

I don't mind doing this again for another example if you wish. Even if you change the public interface on a class, there should not be a ton of classes that need to modified in using it. There should be (in my experience) one or two classes that use it, unless it's a repository or something like that.

Also, test's breaking because you change a public interface isn't really a problem, it's what you would expect. Test's breaking in unrelated areas of the system ARE a problem and are not what you expect.

# November 4, 2009 1:50 PM

Doug Squires said:

My only critique of the Dreyfus model is the place somewhere between levels 2 and 3 where someone derives just enough understanding to become a fanatical zealot...  :)

# November 4, 2009 1:55 PM

Nemanja Trifunovic said:

In fact, tests that are breaking because you refactor are a problem. It makes refactoring too much work, and the automated refactoring stops working.

In my experience, unit tests are just too low level. Acceptance tests will reveal more problems and will not make refactoring painful.

# November 4, 2009 1:56 PM

James W. Shumaker said:

Touche, I definitely fall into that category. I believe that it's from seeing the benefits and not from having a lenient boss who lets me write twice as much test code as I do production code.

I should point out that writing all that test code, completely keeps me out of a debugger, and from using alerts/trace.writelines. I can exercise all of my code without ever running a UI or walking through anything with the debugger. The code is so small, the problems (if there are any) are obvious.

# November 4, 2009 1:59 PM

James W. Shumaker said:

Nemanja, the tdd motto is red, green, refactor. You expect to get red when you refactor and because you're addicted to green tests you do what you have to do to get back to green. Then you remove duplication, make a change, and start over. It keeps you from getting distracted during refactoring and biting off more than you can handle.

The tests are your guide. Anyway, interesting discussion but I'm afraid I'll have to abstain from further comments. Best of luck to you!

E-mail: firstname.lastname@gmail.com

# November 4, 2009 2:02 PM

Wait... Experience matters? When the hell did that happen?!?! said:

I guess it never occurred to James that the reason project B turned out better than project A has more to do with a years worth of experience than the blind devotion to unit tests.

# November 4, 2009 2:13 PM

Paul said:

The author must write lousy unit tests, because just about everything he asserts about unit testing is the opposite of my experience. Most of what he states might be true if you are a dummy and don't know what you're doing. My conclusion: he doesn't know what he's doing.

# November 4, 2009 2:16 PM

YeahRight said:

I regret that I wasted time reading this post.

Unit tests saved my hide this week, and last week, and the week before - after refactoring.

Just hope no noobs read this drivel and believe it.

# November 4, 2009 2:22 PM

ckay said:

Talking about best practice, a writing best practice is to always spell out the first instance of an acronym.  This being the web, hyperlink it man!  Especially 2 or 3 letter acronyms, there are often so many possibilities, and it's nicer than having to google a new acronym every 2 minutes, and try and figure out which one of the possibilities it might be.

TDD -- did you mean Test Driven Development?

# November 4, 2009 2:40 PM

Paul Keeble said:

Good practices don't get taken up by every developer. Just as Java all but replaced C++ for application programming some kept going the way things were. I am OK with that because I like everyone else can choose to hire people that adopted modern practices that study after study have shown to produce more reliable code (see the IBM and Microsoft studies on TDD).

The difference that unit testing gives you is confidence that a piece of work is done. It can be fake confidence if you are not very good at writing unit tests, but with all your missed examples above your code coverage tool will tell you that you missed a case. It is possible to delude yourself and they aren't the complete picture. You also need automated functional and performance tests which are at a higher level to give you that integrated picture of working functionality.

Unit tests are about confidence that something does what its meant to, and that the error and edge cases are handled. It catches bugs before you write them, and no one who has tried it properly would be disagree. Like any skill it needs time to mature before your any good at it, I earnestly suggest you look again before you find yourself the only C++ programmer in the market.

# November 4, 2009 2:42 PM

wsert said:

That will be no more OS-es, no more decent databases, no more games, no more audio and video apps. All we will have is lousy and crappy dragging unit-tested C# and Java throwing null reference exception apps.

Sounds great, where do I resign from a six figure C++ salary for the sake of something that dumps so bad, it is worse than Eclipse overloaded..

# November 4, 2009 2:59 PM

LP said:

Wow - that is a serious piece of rational to not write unit tests. How about you just admit your laziness and move out of the way.

# November 4, 2009 3:00 PM

Rolph said:

And Paul's comment came from a well-tested Firefox or less tested IBM and MS browser, written in C++ that falls appart most of the time.

Hint: use proper C++ devs one, it's called Chrome.

Second Hint: If you want to view this page tomorrow, use a pure 100% Java browser. Guaranteed to load and parse a single page YouTube content within 24h limit.

# November 4, 2009 3:06 PM

Anonymous said:

This article is excellent, not only because it has so many great points but because of the mindset that shines through it. Congratulations!

# November 4, 2009 3:07 PM

James Davidson said:

I am not a huge fan of unit testing, mostly because I don't find it compatible with (A) top-down design and (B) evolutionary design / RAD

Further, my sense is that refactoring is inversely proportional to experience, i.e, if you haven't written a lot of code, you'll probably want (need) to reorganize it more often than if you have a lot of experience.

I strongly support the use of asserts, preconditions, postconditions, etc. Writing down your assumptions protects you, and consumers of your code, from all sorts of errors.

# November 4, 2009 3:18 PM

Len Smith said:

# November 4, 2009 3:41 PM

Jonathan Wright said:

Since Michael Feathers was mentioned, here is a gem of a concluding paragraph from an article titled "The Flawed Theory Behind Unit Testing":

"My point is that we can't look at testing mechanistically.  Unit testing does not improve quality just by catching errors at the unit level.  And, integration testing does not improve quality just by catching errors at the integration level.  The truth is more subtle than that.  Quality is a function of thought and reflection - precise thought and reflection.  That’s the magic.  Techniques which reinforce that discipline invariably increase quality."

http://michaelfeathers.typepad.com/michael_feathers_blog/2008/06/the-flawed-theo.html

# November 4, 2009 3:51 PM

vi said:

Many people here brag how well the unit tests saves them when they refactor code.

Refactoring is like a baby building a sand castle, then he doesn't like some tower, goes and destroys it and rebuilds that part, then etc.

An engineer builds the house once, and that's it. You need to move one wall, you know ALREADY if you can move it or not.

If you're creating a bad house from start, then yes, every time you need to triple check.

I rarely refactor. And the best programmers were probably those who used punch cards in the early beginnings. You needed to know what you're doing.

Testing is like trying to do performance running, while surrounding yourself with huge sponges not to get hurt if you do something bad. No, you go there, you and nature, fail if you did not anticipate, understand your weak points, do better next time.

If your weak point is that you cannot have the whole system in mind when refactoring, and you need an army of tests to maternally reassure you that everything is alright, then maybe it's ok to do it.

I am ok with people who want to write tests. No problem. But I will not write tests. I always check input data though. Some methods I'm told they already receive proper values when invoked. I never check, until I see the first error. Then I go and add all the possible checks - and I never hear about any issues again. I focus on code quality, and it seems I do it enough good enough that people give the respect and come ask for guidance and managers pay attention to what I say.

tl;dr - if you're just starting programming, don't do testing on your spare time coding. Learn the hard way. It will be painful, but you'll write better code in the long run. By the time you'll get into coding critical parts of the systems, you'll have the 6th sense of spotting the issues ahead of time.

# November 4, 2009 3:57 PM

Devlin Dunsmore said:

If you can use Jester and NOT break your tests then you just don't write unit tests properly plain and simple. Also barring a complete overhaul of an entire system unit tests should always be refactorable in a pretty straight forward manner. I mean if you're completely changing class structure and the metaphors associated with a particular code base then of course you are going to have to write completely new tests. As long as you are testing contracts (with some exceptions in testing important pieces of internal implementation) then I much of your refactoring argument is misplaced. Again it comes back to writing proper tests.

I've seen huge projects for major companies fall completely apart and cost hundreds of thousands of dollars to fix because there was no type of automated regression testing, unit or otherwise. But not every project is of that scale.

In the end it's about being Agile and doing what works best for you and your team. Sure TDD and automated testing is said to be a part of Agile development but in the grand scheme of things Agile is all about doing what is necessary and works for you and your team, nothing more. So while I personally disagree with your post given the type of projects I usually work on and my personal preference...whatever works for you!

# November 4, 2009 4:24 PM

Paul said:

Process-driven testing is one of the biggest moves towards professionalism in the recent history of the software industry.

Would you care to rewrite this article in the context of another engineering industry? We'll all laugh politely at how ridiculous it sounds.

# November 4, 2009 4:38 PM

Scott said:

there's a whole lot of fail here. seems to stem from what amounts to a very surface understanding, and wholesale lack of practice, of TDD.

# November 4, 2009 5:31 PM

William Shields said:

Chris,

Excellent post. My mantra is unit tests are fragile and refactoring just means more code you have to fix (being the actual code and all the unit tests).

When theres an immovable deadline often the fixing of unit tests falls by the wayside. The number of times I've seen a suite of unit tests that are mostly broken and once worked is really high.

I particularly liked the point about organisations not trusting their employees. So true. Some want to reduce software development--which they don't really understand--to a predictable, measurable and almost automated process.

As Larry Wall once said, if programming wasn't so hard it wouldn't require humans to do it.

# November 4, 2009 5:45 PM

Chris said:

I like this article. Interesting about Jester, too!

# November 4, 2009 6:29 PM

Echo chamber said:

If your platform isn't one that "likely has great tools for the job [of testing]", is it that testing is useless or that your platform is way out of date?

Get curious about what people outside of the Mothership are doing, open the window and look around sometime. The fresh air won't hurt you.

To the people above blathering on about the uselessness of refactoring and how proper engineering means never saying you're sorry and blah blah blah; I've met a bunch of your types before and the one thing you all had in common is that you never had to live in the houses you built.

No one who's ever had to work a bunch of requirements for a legacy system thinks that unit testing or TDD or refactoring is a waste of time. It's a matter of survival at that point.

Go ask the poor guys who had to come in and clean up your messes what they think of refactoring.

# November 4, 2009 7:22 PM

L-sniffer said:

Hi Cashy,

I had no clue you had a blog. Stumbled upon this on reddit.

Unit tests are a fairly reasonable substitute for documentation. I think of them as living use cases which have become code. Older, obsolete features can be easily negotiated away if nobody can remember why the object ever did that in the first place.

They definitely don't help find bugs, but they do help with change. Specifically changes which affect seemingly orthogonal modules you never even knew existed.

Others here have said that the agile world isn't really about devotion to ideals, it is about what works. There are many parts of unit tests which work. It is important to know what works and what doesn't in both the general and specific.

See ya in space!

# November 4, 2009 7:48 PM

Len Smith said:

From http://blogs.msdn.com/cashto/about.aspx

"Although it's one of the most visible and important apps on Windows Mobile, it's actually fairly prosaic work ... working on various features now and then, but mostly just a lot of bugfixing."

Yet you rant for pages against a process you don't comprehend.

This explains why my last phone was more of a warm paperweight than a phone.

# November 4, 2009 7:48 PM

Sachin said:

you have made very valid points....a great read for me..thanks

# November 4, 2009 8:37 PM

Peter said:

Respectfully:

- Your title doesn't match your conclusion. Which one should I believe, "It's OK Not to Write Unit Tests" or "unit tests aren't a cure-all tonic? (summarized)"

- You make a bunch of good points, notably:

* mutation testing (I can't find a mutation testing tool for .NET)

* the importance of OO design chops,

* interesting point about how functional programming techniques improve code quality,

* the subtleties of overspecifying tests and how hard it is to get it right,

* how acceptance tests are useful as a safety net when making major architectural changes.

These points would have been better received in a separate post titled "things I want you to know about unit tests because I love you, man". See, I've already titled your next post for you, so you won't get in trouble next time around.

- You set up a bunch of strawmen, specifically:

* the emphasis on the Sudoku problem. Math problems (or problems requiring heavy algorithmic thinking) are not well-suited for incremental design via TDD. Instead of being argumentative, you're making observations that might help other sojourners. See, I'm writing your next blog post for you, it's not hard.

* The assertion that unit tests don't catch bugs (and yes I caught your SUBTLE point, but not before reading your UNSUBTLE section title and leading question--which am I supposed to believe again?)

* The strawman argument against corporate standards. It doesn't belong in this piece, except as further railing against dogma which I don't get. Dogma is bad, duh. While we're here: I've recently discovered that THE WORLD IS NOT FLAT, DESPITE WHAT "SOME" "OTHERS" MIGHT BELIEVE. "AIR QUOTES"

- You make an unsupported assertion that eventually programmers outgrow unit tests and that unit tests hamper experienced developers. Maybe it's true. Maybe it's not true. Maybe it's more likely that it's not true, than it's likely that it's true.

# November 4, 2009 9:04 PM

Billy Korando said:

I think the best point was about how developers only write unit tests for the "happy path." Any test is only as good as you make it.

# November 4, 2009 9:55 PM

BigMike said:

Well put Peter!

Sounds to me like Casto is looking for excuses not to Unit Test.  .  . and there goes the baby along with the bath-water.

How about a re-write entitled: "How to write BETTER unit test"? Way more useful and practical.

Finally, that rambling about "trust" in organisations - Dude, you have major personal issues to work through. Nuff said.

# November 4, 2009 10:08 PM

phpslacker said:

Cashto,

I believe you've earnestly tried unit testing. You're aware of the problem of best-practices without context. You mention Object-oriented design principles such as OCP. You even talk about the Dreyfuss model. You're certainly not clueless.

BUT

I can tell from your post just like many others who have posted comments that you're somehow not testing right. I have a sneaking suspicion that you don't TDD at all. You don't practice red, green, refactor. You prolly dont have a CI server. Perhaps you're even white-box testing.

You have a wrong expectation of unit testing

I can only guess but something certainly smells off about ur TDD experience. All i can say is develop some self-awareness consider for a moment that TDD is not the problem. Maybe you are the problem?

You're prolly not as high up on the dreyfuss model as you think you are

Computers do exactly what you tell them to do. Maybe your unit tests truly are fragile and useless. Thats a reflection of yourself not TDD

# November 5, 2009 12:29 AM

Liam Reilly said:

After reading Vi’s comments above, I give up.

I have never met a Developer yet that doesn't refactor. It's not possible to get everything correct first time and it shows huge arrogance and naivety to suggest you can.

Then to go on to say:

"fail if you did not anticipate, understand your weak points, do better next time"

Jesus wept. You cannot seriously tell me that your advice to up and coming programmers is to rely on their instincts and be re-active when bugs are raised.

Quality software should not have bugs. Unit testing is a serious ally in achieving this as are acceptance tests and automated test packs. They are all tools that need to be used wisely and effectively and most importantly, when necessary.

There is no one solution that fits all projects and a good Manager and Developer Lead should recognise that.

# November 5, 2009 3:29 AM

Cors said:

Completely disagree. Unit-tests allow to improve design, catch errors, etc, but only if they are written correctly. If you wrote unit-test just to have them, they doesn't make any sense.

Another points: good unit-tests allow to understand complex pieces of functionality and easy illustrate/fix existing errors.

# November 5, 2009 5:55 AM

Tommy said:

I think all the technicality of names for things you should do is insane. Whether it is Unit, Adversarial or Acceptance Tests. They are all tests. In my book they are all the same thing.

I think the Unit testing frameworks really help you develop Tests of any kind and debug code without having to run (F5) your app get to that point which fails then go line by line to see what happens. With the testing framework you can set up the same scenario that causes the error in code and run the test then make a change. Run the test etc.. etc.. much faster work flow. Test Driven Development just helps you separate your concerns upfront. I am just now learning this technique. Now when I find errors I refactor my app and separate concerns to allow me to "Unit" test the bug. but had I done all this in the first place I could have saved a lot of headache in refactoring. I am not a TDD developer and I do not use unit tests regularly but I do see the advantage and am slowly changing my mindset.

# November 5, 2009 6:22 AM

Liam said:

Tommy,

"They are all tests. In my book they are all the same thing."

I cannot agree with that statement. That's like saying C++ is the same as VB because they are both programming languages. There are fundamental differences and packaging them altogether under the same banner is one of the primary reasons that some organisations fail to benefit from implementing them.

Unit tests test the code and only the code, whereby user acceptance tests or automated testing should test business functionality. Both are valid and work together, but they are not the same. I have seen too many Developers give up on writing Unit tests because they failed to understand how their tests could validate the business requirements, which is not their purpose.

# November 5, 2009 7:24 AM

Miles said:

Maybe the reason testing doesn't work that well for you is you're still an unconscious incompetent.

Where do you work?  Microsoft?

Oh wait, never mind.  I get it now. And before you write me off at being a hater, remember that your company has earned its reputation for writing bad software. That comes from environment and culture.

Beware of engineer's disease: expertise in one area does not mean your automatically an expert in other areas.

# November 5, 2009 8:09 AM

Joe Mama said:

vi demonstrates the clueless arrogance that is the hardened programmer. "I am great, my sh*t don't stink, I never code bugs, and my code is perfect." I challenge you, vi, to post your code somewhere and open it up to scrutiny. I'm betting any amount of money your code sucks the big one.

# November 5, 2009 9:03 AM

Phil Booth said:

Sounds like you are not using TDD. If you're writing your tests *after* you've written your code, then you're doing it wrong and are likely to experience many of the problems that you describe.

# November 5, 2009 9:26 AM

CL said:

"Test what can fail. Test stuff that's easy to test. But don't beat yourself up trying to get 100% code coverage."

Is like:

"It's OK Not to Write Unit Tests"

But not.

There may be some good ideas in here, but I can't find them under the inflammatory assertions.

# November 5, 2009 10:39 AM

orip said:

"Testing is an economic activity like any other."

Of course it is, and I believe this is what your post should have emphasized. You could have discussed common pitfalls on the way to maximizing the value of unit testing.

Instead, you address your post at unit testing zealots, who will probably dismiss you out of hand.

That's too bad, because I think you share good insights, yet still manage to alienate sensible developers who receive good value from unit testing. All you're left with are the anti-unit-testing zealots.

# November 5, 2009 11:03 AM

Pablo Fernandez said:

I don't know what scares me the most... If there's actually writing a post like this (for real) or the fact that SOOOO many people agree with him.

Guys I hope I'll never have to work with any of you.

Regards

# November 5, 2009 11:19 AM

Rick said:

@Pablo: the scary part is not so many people agreeing. The scary part is that *all* of them, including the author, clearly have never bothered to actually to gain any half decent knowledge on the subject.

It's the attitude ("I don't need to no my craft on order to have an opion about it.") that scares me, not the the opinions themselves.

There is some valid criticism of unit testing and TDD.  But this piece is so far of the mark it isn't even funny.

As far as I'm concerned, it's perfectly OK not to write unit tests. As long as you know what your doing and understand the consequences. But 99% of the people dissing unit tests quite clearly have no clue and can't be trusted with such decisions. Unfortunately, they can't be trusted with writing decent unit tests either, as the author unwittingly demonstrates.

Basically they're incompetent with or without unit tests.

# November 5, 2009 12:38 PM

Chris said:

Great article with many valid points, so you can expect to cop a lot of abuse from the zealots. In my experience the class of problems unit testing addresses is trivial and the idea unit tests leads to better design is an absurd illusion.

# November 5, 2009 12:40 PM

Ed said:

Those who have read this article, should read this reply: http://fallenrogue.com/post/234250827/re-its-ok-not-to-unit-test-or-what-you-do-on-your

It's just another point of view.  The one I like best is the point about the author of this post and his ties and experience to microsoft.

# November 5, 2009 2:39 PM

Jon Limjap said:

Hmmm... reading this guy's about page:

"I work on Outlook Mobile, specifically Messaging -- the email / SMS client for Pocket PCs and Smartphones.  Although it's one of the most visible and important apps on Windows Mobile, it's actually fairly prosaic work ... working on various features now and then, but mostly just a lot of bugfixing."

Now I know why Outlook Mobile, and Windows Mobile in general, works so great. Congrats for pwning Apple and their ugly iPhone! ;)

# November 5, 2009 6:43 PM

Charles said:

"I can only guess but something certainly smells off about ur TDD experience. All i can say is develop some self-awareness consider for a moment that TDD is not the problem. Maybe you are the problem?"

I see a lot of these arguments when people question the sacred dogma of TDD.  You might want to read this before ever writing another comment like that again:

http://en.wikipedia.org/wiki/No_true_Scotsman

Do not respond to "TDD sucks for me" with "you are doing it wrong."  The discussion will degrade into "NO U" by the third reply.

# November 5, 2009 9:53 PM

vi said:

To the persons that did not agree with my post above:

a) I never said I write perfect code.

b) I never said I finish it as fast as I might if I'd use TDD.

However your reactions show how once stuck in a comfort zone (TDD oversees and guides and helps and etc) might show an insight on why TDD is needed so much. People are unwilling to change, they think they code perfect until they try TDD which proves them wrong and then they think they saw the light and now they are indeed much much better.

Second, I rarely do refactor because I mainly use the same language for many many years. If I start something new (like coding a game in Flash) where I have no idea what's inside the language, writing TDD doesn't help because I will probably rewrite the whole thing three, four times 'till I get it right.

I also agree that planes for example, they should be tested and retested and retested, etc. Big systems should be retested. However, you need to have the product before starting to test it thoroughly. Of course testing the tire (when not on a plane when it lands) doesn't say that when the plane will actually land, the tire won't blow. You test it at least it has the correct shape that it has to be, but that's about it. You need to have everything in place before starting to really test something - and of course coupled with a very good design initially.

I think that TDD is needed because very few out there are really able to design a system properly. As I don't seem to be one of them (I look up to the real geeky software architects and meta architects) I learned my stuff rewriting from scrap, just to get it better next time.

But it's ok to write unit tests if you want. Is just for me it seems I waste time defending against myself when in fact you should spend that time to code better without 'safety net'. If you fell hard, you learn a lot.

# November 5, 2009 11:10 PM

mohammed hossam said:

mmmmm, Honestly I've never seen such article or blog post before, Unit Tests is one of the safety nets you have around your code, it is not the only one but for sure a very important one, as you said, it helps to make sure that your last bug fix didn't break something else, or the refactor John did yesterday broke something else ...

Also it encourages you to make a better design, and this is not a myth, having the right interfaces is a different discussion, it needs experience and it doesn't come from the first design round, but having the unit tests will make having a next design round possible, because you have less to worry about when making a dramatic change in the code.

Also when will be the first time you execute your code? when you get the UI done?

I think your article is influenced by some bad experiences, but to let the whole idea of unit test down is a completely different thing.

# November 6, 2009 12:04 AM

MrTea said:

"But it's ok to write unit tests if you want. Is just for me it seems I waste time defending against myself when in fact you should spend that time to code better without 'safety net'. If you fell hard, you learn a lot."

But for most of us its not about defending "against ourselves".

It's about ensuring that the client's specifications are met, and that the developer who has to do further work on this code in 2/3/5/10 years time can do so confidently without the terror that their changes may break those client specifications.

# November 6, 2009 1:58 AM

Gilles S said:

Thanks for the debate, I think it's a really interesting article. Too bad some people give oppinions without facts.

In my case, I try to use TDD as often as possible, but I always end up disabling my tests after 2, 3 new versions of the application, since refactoring was required.

Almost everyone agrees that unit tests are great but NOONE really gives numbers about how many lines of code you need to write to test X lines of business code.

I personnaly think that in order to really test 30 lines of complex business code (rule using profile, time of the day and criteria in data), you'd probably need 300 lines of code at least!

Now, given the fact that that business rule might change, you would probably write those tests once but not the second time the business rule changes.

One other argument is that you usually hear more consultants being enthusiastic about unit tests compared to clients who really maintain applications for many years...

I like TDD when you write complex code using layers but maintenance of these tests afterwards is too expensive...

I also think that when people have to deal with a crappy system, they think that if it were unit tested it would not be crappy. But I think that the truth is that an application is crappy mostly because it was baddly designed and coded and not because it was not tested.

Regards

Gilles S

# November 6, 2009 2:36 AM

Awkward Coder said:

I laugh at all the people on here who don't get the ideas behind TDD and agile practices...

Oh and to the author of the post - tests aren't about you, there about the team! If tried to consider other people before your self you might understand this.

# November 6, 2009 3:25 AM

Esko Luontola said:

(You are mostly talking about unit testing, but since you mention also TDD, I'm assuming that you are talking about the kinds of unit tests that are written as part of TDD, before writing code to pass the tests. Writing unit tests after code is out of this reply's context.)

- About your argument of unit tests overspecifying behaviour and being too fine-grained:

If the tests are written in a way that couples them with the implementation, then the tests are badly structured. It's best to write the tests that focus on specifying the desired behaviour and try to keep them as much as possible decoupled from the production code.

Then it will be possible to refactor the implementation, without need to change the tests. There can be minor syntactic changes, if the public API of the system under test is changed, but the intent of the test will stay the same.

But if the requirements of the system change, that is not anymore refactoring, and the tests must be changed. When thinking about tests as a specification of the system's behaviour, then the specifications must of course be changed when the requirements change.

If your "unit" is one method or one class, then that's not a very useful "unit". The "unit" should be "one interesting behaviour" (http://www.infoq.com/presentations/integration-tests-scam), and it's an implementation detail that how many classes or methods are needed to implement it. The test should be decoupled from the implementation. The unit-under-test should be small enough that when a test fails, it will be obvious where there problem is, and the tests should be fast enough to run all your thousands of tests in a few seconds (http://agileinaflash.blogspot.com/2009/02/first.html).

Since you have been experiencing problems with tests that make refactoring harder, that is a test smell that there is a problem in the way that the tests have been written. You should then figure out what that problem is and fix it. Otherwise it's like an artist blaming his paint brush because the painting is not good.

To figure out a good way to write tests, go through the tutorial at http://github.com/orfjackal/tdd-tetris-tutorial (checkout the tutorial branch and read README.html). That will teach you the way I write my tests, in a way that supports refactoring and makes the intent obvious (it took me about 1 year of using TDD to develop this style). Also see the exercises at http://www.cs.helsinki.fi/u/luontola/tdd-2009/harjoitukset

- About the argument that unit tests don't improve the design:

That's both true and false. To be more accurate, tests provide feedback about the design, and they make it possible to change the design. TDD will fail quickly, if the developers are not good at designing, because TDD requires you to change the code many times until it is "done".

When using TDD and making some changes is hard, then the code or the tests are informing you that there might be a design problem. A skilled developer will take advantage of that feedback and improve the way he writes code and tests. A lazy developer will say that TDD does not work, and instead of improving himself he will stop trying and will return to his old ways.

# November 6, 2009 3:45 AM

Liz Keogh said:

I've responded to your post here:

http://lizkeogh.com/2009/11/06/its-ok-not-to-call-them-unit-tests/

Thanks for flagging up some of the common problems I come across all the time with TDD. I hope the suggestions I've made will help people who are having the same difficulties as you are.

# November 6, 2009 4:45 AM

D. Lambert said:

I support the idea of being aware of your objectives as you're writing tests.  If you believe that you've crafted perfect software just because you've got unit tests that pass, then clearly, you're missing the big picture.

Having said that, however, I'm afraid there will be people who jump to some pretty unfortunate conclusions when reading this article.  In my experience, unit tests *do* catch bugs, and they *do* help me refactor, and all the rest of these things, too.  

Although your article doesn't actually suggest that we shouldn't unit test at all for all those reasons, a quick skim of the headings sure suggests that.

I think the balanced view here is that poorly-written unit tests don't really do much to help us at all, even though unit testing can help us when it's done right.  I know this message is in your post, but right now, it's easy to lose that message in the bulletin-board material.

# November 6, 2009 6:27 AM

Brent said:

It's OK Not to Write Unit Tests...

1. If you don't mind the thrashing involved with broken builds and deployments.

2. If you have good automation as your 1st testing step.

3. If you have an elite tester to keep your a$$ in line.

# November 6, 2009 7:30 AM

Jason said:

This is a troll, right?  April Fool's joke?

Or do you really not understand the purpose of automated testing in general?

This article will give you a red face in a year or two (if you're smart) once the usefulness of unit testing clicks for you

# November 6, 2009 10:49 AM

Nirav Assar said:

@James W. Shumaker

I agree with your statements.  Much literature exists on the backing of unit tests and TDD.  I decided to supplement these backing with some simple concrete examples. Here is my post.

http://assarconsulting.blogspot.com/2009/10/perils-of-not-unit-testing.html

In addition, many of the problems cashto has stated are true. For example, the brittleness of tests, where they fail due to the whitebox nature of their testing.  Behavior Driven Development materialized do to these issues.  Just because something good has a few problems when not used properly, doesn't mean it's potential and effectiveness should be diminished.  After all BDD, is TDD done well.

# November 6, 2009 12:53 PM

Of course it is OK said:

Of course it is OK not to write unit test ... to use uncle Bob's analogy, it is OK for doctors not to wash their hands and still get the result. Common, how many times do you see people die because doctors don't wash their hands. It is also OK for mechanical engineers to be sloppy about getting the measure and calculation correct, some machines were built that way and didn't kill people.

So, let's pretend we don't test our code units ... what do we do to know it works, we just put them together and see if the whole thing works? ... Sure it is OK to build software that way ... why not

# November 6, 2009 3:43 PM

Of course it is OK said:

One way or another, smart people will try to incrementally prove that each unit works well before they move on to the next unit ... doing it with TDD or BDD or other ways ... you are doing unit testing anyway ... do you run them all the time? do you automate them? do you just verify them once and throw them away so that you don't have to maintain them? ... anyway, you need to verify things in smaller units to be efficient ... and to me that's unit tests ... you might not want to automate and maintain them ... that's your choice ... but says you don't have to write unit tests ... I don't know what you do to make it works for you, I am interested to know ...

# November 6, 2009 3:53 PM

TDD-guy said:

  Unconscious incompetence. It’s about this post. Saying this I don’t say something really bad about author – this is a specific stage of getting new knowledge – that’s how our brain works.  It seems that author knows a lot about unit testing, but completely missed TDD (test-first) approach as a design but not test activity. Maybe he is on his way of discovering this. If we take into account this, author described his personal difficulties (or difficulties of his team) with unit testing. From this perspective his point become at least understandable (here I try to be not such emotional as Uncle Bob). Of course Cashtro’s conclusions are illogical and instead of discrediting the whole idea of unit testing he should assume existing different ways of writing unit tests and try to learn them.

  I heard similar point from a lot of  people (who are not doing real TDD), so as for me he didn’t say something new,  but I found other aspect very interesting: his post become extremely popular very quickly.  May be that was a tricky provocative act? :)

----

Cashtro: don't be dissapointed about all the comments and feedback, please continue writing! I hope some day you will write excellent post with constructive criticism of TDD/test-first as a design activity!

# November 8, 2009 2:08 AM

Anon said:

PROTIP: If you're making private methods public to test, or if refactoring breaks test that shouldn't be breaking, you're doing it wrong. It's also possible your platform/project/language is doing it wrong, and you just inherited that.

This is pretty common given that almost no language comes with support for unit testing out of the box, and many projects are older than unit testing best-practices.

# November 16, 2009 12:49 PM

Paolo said:

" Unit Tests Give Me Confidence When Refactoring!  "

" Unit Tests Catch Bugs! "

In my last experience are true statements. I'm talking about case of software that translate (or transform)  different formats (for example PDF more some rules is input and XML is output ), where interactions (like DB / net) does not exist, only processing. In this case Unit Tests are fundamentals during refactoring.

But my unit test, can test a transformation, the matter is the boundaries of the test.. I test a single class, no DB or network is involved, but this test involves almost all code and logic (including multi thread programming). I wrote a UNIT test ? Or a normal test ?

I would not be so stringent about the unit test definition, the point is to write a useful test (sometime is not easy or convenient).

# November 18, 2009 2:06 AM

Ben said:

Repeat after me: Don't test private methods.

Why you would want to be a bit beyond me - all you are interested in is the visiable behaviour of the 'unit'. Which directly implies that you should be testing the public interface.

It's also not too hard to write tests that take more than the 'happy path', particularly if you're using TDD.

I am rather partial to your take on organisational standardisation though :)

# November 18, 2009 8:38 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker