Unit testing is not (generally) useful
prehacked.com
prehacked.com
But if you want to take the argument seriously, I would say that "finding bugs" is not the primary reason I write unit tests anyway. It's to prevent regressions, and make me feel safe that I haven't broken anything after a refactoring. If not for my unit tests, I'd be scared to change much of anything, for fear of stirring up a whole bunch of trouble that I'll have to fix later on.
Adding known bugs to the unit test suite is a good way to prevent regressions.
Here's a common scenario that made me want to write tests. I want to implement feature A, but to make it work, I'm first going to have to write library B and C. So I write library B, but there is no way to test it in the program yet, because feature A doesn't exist. Right after I've finished the code, I have a pretty good idea of where things might go wrong, and what corner cases I want to exercise. But by the time I finish library C and then get around to implementing feature A, I've forgotten that stuff. Pain points go unaddressed.
In summary, unit tests really start to show their value when you're working on a program that's too big to fit into your head all at once.
Testing is only a piece.
That's certainly not unit testing though.
Fully automated is necessary so you can run them frequently, automatically, near-continuously.
But beyond that, I think you get into religious territory, and I think people getting dogmatic about the definition of "unit test" tends to mistake definition for virtue (a common failing). If you've got automated testing, great! You win. Doesn't matter how it works.
Or, rather, it does matter, but only within your context, which nobody else is really competent to judge you on.
For me, if I had unit tests everywhere, I'd be scared to change much of anything, knowing that after the refactoring, and usual testing/checking things work, I'd then have to rewrite/fix unit tests.
Whatever it's called, it's not quite as fine grained as a unit test and it's not as large in scope as integration testing. It's at the level of your business specs. So the only time you'll break your tests is if you've jacked up a spec.
Honestly, if my changes cause new behavior in the system but the people paying me won't care, then I don't care either.
But slightly higher level tests can be written to almost never have this problem. Let's say you've written code to ensure that a CC transaction doesn't go through with an invalid number. No matter what the implementation looks like - no matter how much you refactor - this test should always work. The same is true for a wide range of useful tests. (These aren't strictly "unit" tests, but they fall into a similar category.)
My personal experience is that a good unit test suite is 99% useful when refactoring, and 1% painful.
Writing unit tests up front forces me to write the code in a way where inputs & outputs can easily be stubbed out, which in turn makes writing messy interdependencies simply too hard!
Basically, if I write with unit tests, it becomes easier to write maintainable code, and harder to write unmaintainable code.
My claim isn't really that they don't work, it's that (compared to the other things I listed) they have a tiny ROI.
People that do unit tests do all that stuff too!
Your lack of specs also has nothing to do with unit testing. It might dictate the difficultly in writing acceptance tests, but that's a completely different subject.
I don't feel the need to proselytize unit tests since you've already written them off, but what's the point to posting about why you don't like something only to back it up with some sort of rambling, incoherent analogy that you probably don't even believe?
The point was that the ROI on unit tests is almost always very much lower than the ROI of the others. So when time gets tight (as it always is in a startup), you should generally put effort into all the other things and not into unit tests.
When I was part-way into coding this thing, I took a day to go through all the code and write tests for anything I could. I found a few bugs, so I could at least say that it helped somehow. But the tests have helped a lot more when I added to it - it feels -good- to see a big green bar light up whenever I add something. It's -nice- to run all tests, leave it a minute, and confirm that it's not going to blow up before I have to demonstrate to anybody. Of course, finding bugs is nice, and I set up a better testing rig to make sure it doesn't fail on anything I haven't thought of, but the benefits of unit testing go further than bug detection.
When you're all crestfallen with no desire to code, finding bugs is only secondary.
Personally, just making something people want is enough motivation for me ;-)
In my experience, the more common bugs are integration bugs, scaling bugs, weird memory usage issues, not to mention interfacing to external systems - for example some weird browser comes along and does idiotic requests you'd never expect a sane person to do.
Those things are very hard to test for, and don't really produce a good ROI as abstractbill says... Best just to log things, graph things where possible, spot weirdness, investigate and fix.
What I suspect is that all of us have basically the same idea in mind, and what we're disagreeing over is mostly semantics and context.
Btw, all of my unit tests include memory usage validation. It's easy in c and c++, but I'm not sure how it would be done in a web development environment.
To use the doctor analogy, I would say unit testing is more about testing patient outcomes when they are put through varying courses of drugs or treatments (fixing bugs and adding new features) rather then trying to make them die before declaring them healthy. Is the patients blood pressure normal? Check. Now the patient wants to start some treatment for something else. Oh wait, I'm getting an abnormal blood pressure reading.
I don't know what he's using there at Justin.tv, but most languages that are more rigid (than Smalltalk or Ruby for example) are certainly not quite as nice for unit testing.
My point is that unit tests aren't cost-free, and their ROI is awful for most things.
Step 1: If you're thinking about how a code api should act, sketch it out inside a test.
Step 2: If you're about to jump into a repl and poke at your code, open a unit test instead.
Now you've simply replaced other activites at no net cost to you. My core takeaway is that everyone tests their code somehow. You're best off if you can automate that process. Don't obsess over it (I almost never test my html/views), but try to find opportunity.
The models testing is obvious. What you're referring to there is controller testing. In Rails/Rspec, the way you do that is by mocking/stubbing the models (so you're only testing the controller logic). Then you pass in the parameters that would come in from the web, and check that the controller code (which should be fairly straightforward) behaves appropriately.
This article explains this approach quite clearly: http://www.patmaddox.com/blog/2007/9/15/easy-controller-test...
Appendix F - Personal Observations on Reliability of Shuttle http://www.ralentz.com/old/space/feynman-report.html
A good summary is at http://duartes.org/gustavo/blog/post/richard-feynman-challen...
The consequences of a bug are usually very small. It's also very obvious if a bug is causing you pain.
After you've got real app code the tests serve more or less as regression tests to make sure I haven't broken anything major deep in the guts of my models and such.
In short, like some of the other comments here: Unit tests aren't for finding bugs, they're for helping you not write the bugs in the first place.
Let's look at a scenario where you are using an outside framework.
Not writing tests for your code? Framework v2.0 comes out and you want to use a great new feature in that version. Will your app work if you upgrade? Sure you'll have to test/QA your app regardless, but with tests you might have a better idea of where to look for problems.
This is what I'm facing at the moment as a single developer. The app has no test coverage so updating is a laborious process of testing everything by hand.
But getting into testing has it's own problems. The biggest I have with testing is when I read discussions about bugs within the test framework. How much time will you spend working around bugs in the testing framework?
Some of my perspectives:
class/function level unit testing is only needed for common library code.
component level unit testing is critical if you want to do any significant refactoring.
non trivial integration tests (especially timing sensitive multithreaded code) can find many subtle bugs that would be too late to find in production.
I've written a few tests (for a database engine) that paid themselves many times over.
I do have a habit of assuming every other hacker is doing some kind of a startup, so this is a fair point.
Unit testing is like vaccination: it's good for me that I'm vaccinated against smallpox, but it's also really good for you that I won't be getting sick and giving it to you, and your ability to avoid vaccination (or testing) and still function is often directly correlated to how well everyone else is vaccinated (or how well they've tested their code so you know when you're breaking it).
Those don't always have to be unit tests in the strictest sense, so you could perhaps argue that a test that breaks as a result of unrelated changes isn't really a "unit" test because it wasn't properly isolated, but I really hate those sorts of language arguments. I'll call something a "unit" test if it's not an "end-to-end" test, even if I didn't mock or stub out every possible dependency. And it certainly sounds like the author of this post is arguing against unit tests in that sense rather than in the stricter sense.
Not unit testing is like building a car door and not check that it fits until all parts are to be assembled, and then reviewing what's wrong. Dumb.
But I can see how right now it seems their time is better spent on other things.
I did some testing, but not much when I worked for a startup.
If one bad programmer writes the unit tests, and another bad programmer writes the code, then you might end up with a mediocre outcome, instead of a bad outcome. Same with pair programming.
Likewise, if you get a good programmer to write the unit tests, then give the programming work to a terrible programmer, given enough time, he'll write a working solution.
But TDD benefits even the best programmers when they are dealing with a huge, ugly, old code base.
When on the other hand you're user testing every day or multiple times a day, like you might with a web startup, then TDD may only slow you down.
These days I'm at a point where I can usually push 4 or 5 new releases into production every day. It's pretty awesome :-)