Unit Testing Best Practices

Tools for Unit Testing Success

This paper is part of a series of interviews in which Adam Kolawa—Parasoft CEO and Automated Defect Prevention: Best Practices in Software Management (Wiley-IEEE, 2007) co-author—discusses why, when, and how to apply essential software verification methods. The series also addresses code analysis, code review, memory error detection, message/protocol testing, functional testing, and load testing. In this interview, Kolawa counters claims that unit testing has peaked, explains how unit testing delivers value above and beyond “early testing,” and warns that code coverage is not the best measure of test suite completeness. Read on to learn how unit testing can help your team rapidly modify code with confidence—and how to get started as painlessly as possible.

Unit testing seems much more popular in theory than in practice. Why do you think that’s the case?

Well, there’s a huge barrier to entry because setting up realistic and useful tests can be quite complex. People tend to have a good understanding of how the application is supposed to work from the outside—how it’s supposed to respond to different user actions or operations—but they have a limited grasp of how it’s supposed to work “under the hood.” This is quite a handicap when it comes to writing unit tests. With unit tests, you need to create relevant initial conditions so the part of the application you’re trying to test behaves like part of the complete system. If these initial conditions aren’t set correctly, the test won’t be exercising the code in a realistic context, and it won’t be terribly useful to you. You can’t really tell if something is working properly if you’re not testing it under realistic conditions. The context is critical. For instance, a beam might provide proper support under many conditions… but if you’re building with it, you really need to know if it will hold up under your specific construction. If it wasn’t verified to work in a similar context, you can’t rest assured that it will work for you here. Creating the initial conditions can be difficult, but it’s absolutely essential. I think the people who do try to accomplish this are frustrated by the amount of work required, and those who don’t are disappointed that they’re not getting valuable results.

There’s been a lot of debate lately about whether unit testing is going the way of the dinosaur. What do you think?

I think that unit testing is more valuable now than ever. But I think we need a different flavor of unit testing than the one everyone always focuses on, which is early testing. Let me explain. The systems we’re building today, such as SOA and RIA, are growing in size and complexity—plus developers are being asked to evolve them faster than ever before. We typically have a good idea of what functionality we need to test because the use cases are usually well-defined in requirements. However, it’s difficult to test them in their entirety because they are so complicated—they are connected to the outside world, staging systems are difficult to establish and maintain, each test requires considerable setup, and so on. It might be feasible to test each use case once, but you really need to test all your use cases daily so that you’re immediately alerted in case your constant modifications end up breaking them.

And that’s where unit testing comes in?

Yes. Unit testing allows you to continuously test parts of the application without the hassles of dealing with the complicated system. Using a technology like Parasoft Tracer, you can create unit test cases that capture the functionality covered in your use cases. From the application GUI or using a SOA or Web test client, you just exercise your use cases while Tracer is enabled. As the use case is executed, Tracer monitors all the objects that are created, all the data that comes in and goes out, and then it creates you a unit test that represents this operation—and even sets up the proper initial conditions. You can then take this unit test case and execute it on a separate machine, away from the original system. This means that you can use a single machine—even a standard developer desktop—to reproduce the behavior of a complicated system during your verification procedure. Add all of these tests to your regression test suite, run it continuously, and you’ll immediately be alerted if this functionality that you captured is impacted by your code modifications. Essentially, this helps you address the complexity of today’s systems in two ways:
  • It relieves you from having to perform all the time-consuming and tedious work required to set up realistic test conditions.
  • It gives you a test case that you can run apart from the system—a test case you can run continuously and fully automatically.

So unit tests are created after the application can be exercised realistically. How does that mesh with the idea that unit testing is early testing?

This type of unit testing is not early testing at all. It’s a completely different flavor of unit testing, and I think it’s even more valuable than early testing. But, there’s still a time and place for early testing... Learn more about how to automate unit testing with Parasoft.