views:

570

answers:

12

Hi, I am recently introduced to the test-driven approach to development by my mentor at work, and he encourages me to write an unit-test whenenver "it makes sense." I understand some benefits of having a throughout unit-test suite for both regression testing and refractoring, but I do wonder how often and how throughout we should write unit-test.

My mentor/development lead asks me to write a new unit test-case for a newly written control flow in a method that is already being tested by the exsisting test class, and I think it is an overkill. How often do you write your unit tests, and how detailed do you think your unit tests should be? Thanks!

+21  A: 

Technically, if you're following strict Test Driven Development...you should be writing your Unit Tests after you have spec'd any portion of your application. You should be going from:

User Requirements -> Function Design -> Unit Tests -> Code

Remembers, Tests come before Code in TDD.

Justin Niessner
And a nice illustration here : http://blog.typemock.com/2008/12/starting-test-driven-development-using.html
m_oLogin
-1: If you're following strict Test Driven Development, the code is produced in a cycle of *Test* (in the singular) -> Code -> Refactor -> Another *Test*, not all the tests before the code.
quamrana
A: 

As Justin said, you should be writing your unit test before you write the code.

While this is probably the best thing to do, it is sometime overkill. Depending on the projet I sometimes write a unit-test only for every bug I find (and solve).

Sure, I probably miss some of them, but my unit-testing becomes more and more efficient with the time and I'm pretty sure that I will never miss a corrected bug.

ereOn
+1  A: 

Unit tests should give you confidence, that the code you write, does what you want. Therefore you should write as many tests as it's needed to give you this confidence.

Dominik
A: 

Unit tests will:

  • give you the confidence to make refactoring changes while knowing that you're not breaking anything else.
  • act as a sort of "living documentation" of your code, allowing others to know exactly how the code will behave in various circumstances.
  • when following strict TDD as described by @Justin, passing all the unit tests written before you started writing code will let you know when you are "done" coding. In my experience this also leads to greatly simplified and easier to understand (cleaner) code.

As your mentor mentions, you should only write unit tests that make sense. The rule of thumb I use is that I try to write unit tests for pieces of code that execute business logic. I generally don't write unit tests for bean classes with little more than getters and setters.

Unit tests usually become more valuable with time as they are expanded and enhanced to deal with bug fixes and other code enhancements made after the initial delivery.

Vinnie
+5  A: 

You should write a unit test whenever you write any code. And, as other have pointed out, in TDD you write the tests before you write the code.

If you think it is overkill, ask yourself "if I don't test this code, how do I know it works?"

Bryan Oakley
The only problem is that writing tests doesn't tell you it works either, only that it passes whatever tests you happened to think of.
darron
@darron that's why you base the tests on a functional design. The tests tell you that it complies with the requirements.
Jack Ryan
@Jack: A successful test tells you that the code does what the test is expecting and is no guarantee that the actual requirements are fulfilled. One of the most common problems I run into when checking bugs in our software is that the developer misunderstood the requirements, wrote incorrect tests, then incorrect code and hence had the impression that everything was ok, since the tests are not failing.
jarnbjo
... but the point remains, if you don't write tests for a block of code you just added, you have no way of knowing if it works or not. At least if you wrote tests you can prove that it works according to some specification (the specification being, what the tests check for).
Bryan Oakley
A non-TDDer would simply run the program, watch it do what they expect, and 'know' it works. I doubt many of them would find the 'only way you know it works' argument convincing
David Sykes
@David: yes... especially considering there's absolutely nothing magical about test code. It can certainly be buggy too.
darron
TDD tells you that your code passes the tests you happened to think of, which hopefully are not buggy, which hopefully match and completely cover the functional design, which hopefully matches your requirements, which of course the developer(s) perfectly understood from the user champion. I find it exceptionally hard to buy this "know it works" argument.
darron
@darron i disagree: if you ONLY write code which fulfill your tests, and nothing more, your tests by very definition become the specification. that means you don't only have the tests "you happened to think of"...your tests define what your code is supposed to do, and your code really does nothing more than that! Your remarks are more fitting to writing unit tests "after the fact": there you truly don't have the security you'd want.
Epaga
@Epaga: Sorry, that's ridiculous. Say a developer is a rookie who's never heard of some locales reversing "," and "." in numeric fields. Even writing tests first, and only coding to the tests... his tests are all going to pass! It's still a bug, and you can't possibly expect to tell a client that "It works as specified" when this comes up. This is a simplistic example problem, but thinking it through means that TDD cannot possibly let you "know" anything at all... except simply the fact that it appears to pass the tests that *you happened to think about* and that you hopefully wrote correctly.
darron
@darron good example, though if you had functional tests in place, they'd have caught that, assuming you / the client remembered to specify that i18n and localization is to be respected. That's where BDD can be very helpful.
Epaga
@Epaga: yes, but that was just a simple example. Imagine the impossibility of TDD helping on something like the Intel floating point bug some time ago. I really don't like the assertion that using TDD means you can "know it works".
darron
A: 

There is a fundamental thing about unit tests when doing test driven development, namely that the unit tests describe functionality. If the test does not define e.g. how null inputs behave, then you cannt expect it to work.

Thorbjørn Ravn Andersen
+1  A: 

Writing tests, and more importantly testable code is an independent skill, just like learning to program each new language is an independent skill.

Read Miško Hevery's blog, read some books (I liked Test Driven by Lasse Koskela), use some code coverage tools like Clover, and then write some tests.

As you write tests, your testing skills will improve, and you will come to understand what is involved in writing testable code. Then you will be able to know for your particular project the level of code coverage that is required.

David Holbrook
+2  A: 

My mentor/development lead asks me to write a new unit test-case for a newly written control flow

How did that control flow come to be written, unless it was needed to pass a failing test? By the definition of TDD, no production code will come to existence, unless there first exists a failing test which requires that piece of code to be written. So you must have been writing the code using some test-last technique and not TDD.

I recommend you to read the article The Art of Agile Development: Test-Driven Development. You can practice TDD using this tutorial.

I think that your mentor using the phrase "whenever it makes sense" can be harmful, especially to people new to TDD, because it's not possible for one to make a good decision about that until after have many years of experience, after one has reached Ri-level. On one occasion when Kent Beck decided to not write a test, it was appropriately commented by Ron Jeffries: "I trust you, and about three other people, to make good short game decisions."

You should always write a test first. Anything that could possibly break requires a test. Only things that could never break, because of somebody changing the code, don't need tests. For example declarative code rarely breaks: static HTML layout code on a web page is generally not worth testing automatically (you must test it manually to see whether it looks right), but anything dynamic is worth testing.

Esko Luontola
A: 

You should always write test, if your existing testsuite is insufficient. The best sign, that your tests are not enough are bugs. So a good practice is to write a unit-test for every bug you encounter. With test-driven development you should start with some test, do define the functionality of a class. test-coverage-tools gives you some hints, which parts could need more testing.

Mnementh
A: 

The right/thorough answer for this question must be long as this is key question for every testing process, but I'll answer with following simple(?) rules:

  1. If some use case is important write separate test for it so someone else (or you in the future) may spot that case by reading or failing the tests.

  2. If you are wondering longer than 5 seconds if something is important enough to test or not then assume it is :-)

  3. If by any chance testing this case is very hard/expensive complain about this to your manager / tech lead and skip writing the test.

koppernickus
A: 

Personaly I use unit tests, when I have massive data, and I dont want to copy/paste a lot of System.out.println, and check them one on one. With Unit tests, you lose 1h to write them, and save a lot of them testing. For trivial stuff, I rather use the println tecnic, or check the debug variables.

StackPointer
+1  A: 

I too have become a recent convert to TDD and I find it extremely helpful. The idea is such that as soon as you have a spec, you start writing unit tests. Once your tests have been written, a large majority of your code can come from those tests. What remains in your tests are the basis of your asserts and you then have a very good repeatable pattern for - write test, implement code, confirm through asserts, continue. Good stuff!

Derek