July 19, 2011

TDD 101 Learning Series – Writing Good Unit Tests Webinar Recording and Q&A

Events
Thanks to everyone who joined us for the second event in our TDD 101 Learning Series. If you missed the event, take about 25 minutes to watch the Writing Good Unit Tests recorded webinar. Attendees asked several interesting questions, all of which we weren't able to address during the webinar. To follow up, and invite others to participate, we've included a complete Q&A below.

Writing Good Unit Tests Q&A

How do you start adding unit tests for existing code, which may not have been originally written with unit tests in mind? The next webinar is Beginning Test-Driven Development in a Legacy System, and I’ll be covering this topic in much more detail. Even if you are just looking at unit tests, the next webinar should be helpful. The basic idea is that you’re going to have to refactor and there are quite a few tips and tricks you can use to reduce effort and boost results. Anything you touch should be refactored so that you can write unit tests. It can be daunting, so start small! How can a unit test NOT depend on the interface of the unit it’s testing? It is going to depend somewhat on the interface but you really don’t want it to be too heavily dependent. For example, if I have fifty places in fifty different unit tests where I am creating an object and then calling five methods on each to further initialize the object, I am really dependent on that interface. If any of those methods changes, I am going to have a lot of find/replace work to do. When you realize that you’ve got a lot of duplications in your unit tests, just like within code when you’re coding, that’s a great opportunity to go ahead and pull that logic out into one centralized place. For example, put the five function calls that initialize the object into a constructor that can be called once. If the interface changes, you just have one place (the constructor) to update and you’re all set to continue running your unit tests. Can you differentiate between regression tests and unit tests? The biggest difference is the motivation for the test. In practice, if you look at a test, you may not be able to say this is a regression test or a unit test. Unit tests verify the functionality of a specific section of code, while regression tests verify that everything still works after a code change. Regression testing looks for regressions, or old bugs, that have come back. Regression testing can involve running unit tests, but is not limited to only unit tests. When should the unit test be written? When the design is clear, when requirements are clear, or...? If you’re doing TDD, there is not going to be a big design up front because requirements are typically represented by user stories. When you write tests for TDD, you are using them to drive the development, so they should be written before the code. If you’re not practicing strict TDD, it’s still a best practice to write the tests and the code at the same time. The unit tests are testing the individual pieces of the code, so the tests and code should really be written and maintained as one unit. Are some languages harder or easier than others, when it comes to writing unit tests? Absolutely. I would say C++ is a very hard language to write unit tests in. C# is far easier and Java is a pretty easy language to write unit tests in as well. There are a lot of different IDEs that you could look at to see what kind of testing frameworks they have, what is supported, etc. How about unit testing Getter and Setter methods that trim empty space? Is a behavior like that worth testing? That’s a gray area. Do they really only trim empty space? How important is trimming the empty space? Would it break anything if they suddenly stopped trimming empty space? If the behavior is expected and relied on, I would write unit tests for it. If it won’t break the application if the extra functionality doesn’t work (maybe only cause UI issues), then it’s a judgment call. For cross-platform apps, how do you deal with tests that check for OS-specific output? Should I write OS-specific tests or write generic ones and ignore failures from tests relevant to a different OS? My recommendation is to define a constant to the expected result for each OS. Then, use the constant for the test. For example, I have the following code in a C++ program:
#ifdef _WINDOWS

    const CTTString baseDir = “C:baseDir”;

#else

    const CTTString baseDir = “/Volumes/Storage/Code/baseDir”;

#endif
What resources can you recommend for more information about unit testing best practices and guidelines? There are a number of great books out there. I like the XP Series that covers Extreme Programming practices. I also ran across this blog, which I think lays things out clearly: http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/