views:

314

answers:

7

What are some of the tricks or tools or policies (besides having a unit testing standard) that you guys are using to write better unit tests? By better I mean 'covers as much of your code in as few tests as possible'. I'm talking about stuff that you have used and saw your unit tests improve by leaps and bounds.

As an example I was trying out Pex the other day and I thought it was really really good. There were tests I was missing out and Pex easily showed me where. Unfortunately it has a rather restrictive license.

So what are some of the other great stuff you guys are using/doing?

EDIT: Lots of good answers. I'll be marking as correct the answer that I'm currently not practicing but will definitely try and that hopefully gives the best gains. Thanks to all.

+4  A: 

Write tests before you write the code (ie: Test Driven Development). If for some reason you are unable to write tests before, write them as you write the code. Make sure that all the tests fail initially. Then, go down the list and fix each broken one in sequence. This approach will lead to better code and better tests.

If you have time on your side, then you may even consider writing the tests, forgetting about it for a week, and then writing the actual code. This way you have taken a step away from the problem and can see the problem more clearly now. Our brains process tasks differently if they come from external or internal sources and this break makes it an external source.

And after that, don't worry about it too much. Unit tests offer you a sanity check and stable ground to stand on -- that's all.

carl
The hint with forgetting about test code is nice => +1
furtelwart
+10  A: 
  1. Write many tests per method.
  2. Test the smallest thing possible. Then test the next smallest thing.
  3. Test all reasonable input and output ranges. IOW: If your method returns boolean, make sure to test the false and true returns. For int? -1,0,1,n,n+1 (proof by mathematical induction). Don't forget to check for all Exceptions (assuming Java). 4a. Write an abstract interface first. 4b. Write your tests second. 4c. Write your implementation last.
  4. Use Dependency Injection. (for Java: Guice - supposedly better, Spring - probably good enough)
  5. Mock your "Unit's" collaborators with a good toolkit like mockito (assuming Java, again).
  6. Google much.
  7. Keep banging away at it. (It took me 2 years - without much help but for google - to start "getting it".)
  8. Read a good book about the topic.
  9. Rinse, repeat...
jasonnerothin
+2  A: 

Read a book like The Art of Unit Testing will definitely help.

J.W.
+1  A: 

As far as policy goes read Kent Beck's answer on SO, particularly:

to test as little as possible to reach a given level of confidence

Write pragmatic unit tests for tricky parts of your code and don't lose site of the fact that it's the program you are testing that's important not the unit tests.

sipwiz
+1  A: 

I have a ruby script that generates test stubs for "brown" code that wasnt built with TDD. It writes my build script, sets up includes/usings and writes a setup/teardown to instantiate the test class in the stub. Helps to start with a consistent starting point without all the typing tedium when I hack at code written in the Dark Times.

MikeJ
+1  A: 

On my current project we use a little generation tool to produce skeleton unit tests for various entities and accessors, it provides a fairly consistent approach for each modular unit of work which needs to be tested, and creates a great place for developers to test out their implementations from (i.e the unit test class is added when the rest of the entities and other dependencies are added by default).

The structure of the (templated) tests follows a fairly predictable syntax, and the template allows for implementation of module/object-specific buildup/tear down (we also use a base class for all the tests to encapsule some logic).

We also create instances of entities (and assign test data values) in static functions so that objects can be created programatically and used within different test scenarios and across test classes, whcih is proving to be very helpful.

RobS
What's the name of the tool? Free/open source?
fung
It's something I wrote myself (took all of about an hour, plus tweaks to the templates over time) but it's easy enough to accomplish - I'll write a blog entry about the approach shortly
RobS
+1  A: 

One practice I've found very helpful is the idea of making your test suite isomorphic to the code being tested. That means that the tests are arranged in the same order as the lines of code they are testing. This makes it very easy to take a piece of code and the test suite for that code, look at them side-by-side and step through each line of code to verify there is an appropriate test. I have also found that the mere act of enforcing isomorphism like this forces me to think carefully about the code being tested, such as ensuring that all the possible branches in the code are exercised by tests, or that all the loop conditions are tested.

For example, given code like this:

void MyClass::UpdateCacheInfo(
    CacheInfo *info)
{
    if (mCacheInfo == info) {
        return;
    }
    info->incrRefCount();
    mCacheInfo->decrRefCount();
    mCacheInfo = info
}

The test suite for this function would have the following tests, in order:

test UpdateCacheInfo_identical_info
test UpdateCacheInfo_increment_new_info_ref_count
test UpdateCacheInfo_decrement_old_info_ref_count
test UpdateCacheInfo_update_mCacheInfo
Eric Melski