How to write good Unit Tests?

21,761

Solution 1

An important point (that I didn't realise in the beginning) is that Unit Testing is a testing technique that can be used by itself, without the need to apply the full Test Driven methodology.

For example, you have a legacy application that you want to improve by adding unit tests to problem areas, or you want to find bugs in an existing app. Now you write a unit test to expose the problem code and then fix it. These are semi test-driven, but can completely fit in with your current (non-TDD) development process.

Two books I've found useful are:

Test Driven Development in Microsoft .NET

A very hands on look at Test Driven development, following on from Kent Becks' original TDD book.

Pragmatic Unit Testing with C# and nUnit

It comes straight to the point what unit testing is, and how to apply it.

In response to your points:

  1. A Unit test, in practical terms is a single method in a class that contains just enough code to test one aspect / behaviour of your application. Therefore you will often have many very simple unit tests, each testing a small part of your application code. In nUnit for example, you create a TestFixture class that contains any number of test methods. The key point is that the tests "test a unit" of your code, ie a smallest (sensible) unit as possible. You don't test the underlying API's you use, just the code you have written.

  2. There are frameworks that can take some of the grunt work out of creating test classes, however I don't recommmend them. To create useful unit tests that actually provide a safety net for refactoring, there is no alternative but for a developer to put thought into what and how to test their code. If you start becoming dependent on generating unit tests, it is all too easy to see them as just another task that has to be done. If you find yourself in this situation you're doing it completely wrong.

  3. There are no simple rules as to how many unit tests per class, per method etc. You need to look at your application code and make an educated assessment of where the complexity exists and write more tests for these areas. Most people start by testing public methods only because these in turn usually exercise the remainder of the private methods. However this is not always the case and sometimes it is necessary to test private methods.

In short, even experienced unit testers start by writing obvious unit tests, then look for more subtle tests that become clearer once they have written the obvious tests. They don't expect to get every test up-front, but instead add them as they come to their mind.

Solution 2

While you've already accepted an answer to your question I'd like to recommend a few other books not yet mentioned:

  • Working Effectively with Legacy Code - Michael Feathers - As far as I know this is the only book to adequately tackle the topic of turning existing code that wasn't designed for testability into testable code. Written as more of a reference manual, its broken down into three sections: An overview of the tools and techniques, A series of topical guides to common road blocks in legacy code, A set of specific dependency breaking techniques referenced throughout the rest of the book.
  • Agile Principles, Patterns, and Practices - Robert C. Martin - Examples in java, there is a sequel with examples in C#. Both are easy to adapt to C++
  • Clean Code:A Handbook of Agile Software Craftsmanship - Robert C. Martin - Martin describes this as a prequel to his APPP books and I would agree. This book makes a case for professionalism and self-discipline, two essential qualities in any serious software developer.

The two books by Robert (Uncle Bob) Martin cover much more material than just Unit testing but they drive home just how beneficial unit testing can be to code quality and productivity. I find myself referring to these three books on a regular basis.

Solution 3

  1. With test driven design, you normally want to write the tests first. They should cover the operations you're actually using/going to use. I.e. unless they're necessary for the client code to do its job, they shouldn't exist. Selecting test cases is something of an art. There are obvious things like testing boundary conditions, but in the end, nobody's found a really reliable, systematic way of assuring that tests (unit or otherwise) cover all the conditions that matter.

  2. Yes, there are frameworks. A couple of the best known are:
    Boost Unit Test Framework
    CPPUNit

    CPPUnit is a port of JUnit, so those who've used JUnit previously will probably find it comfortable. Otherwise, I'd tend to recommend Boost -- they also have a Test Library to help write the individual tests -- rather a handy addition.

  3. Unit tests should be sufficient to ensure that the code works. If (for example) you have a private function that's used internally, you generally don't need to test it directly. Instead, you test whatever provides the public interface. As long as that works correctly, it's no business of the outside world how it does its job. Of course, in some cases it's easier to test little pieces, and when it is, that's perfectly legitimate -- but ultimately you care about the visible interface, not the internals. Certainly the whole external interface should be exercised, and test cases generally chosen to exercise the paths through the code. Again, there's nothing massively different about unit tests versus other kinds. It's mostly just a more systematic way of applying normal testing techniques.

Solution 4

Nowadays, Test Driven Development is the approach for managing big software projects with ease.

That is because TDD allows you to make sure after each change that everything that worked before the change still works, and if it doesn't it allows you to pinpoint what was broken, much easier. (see at the end)

What is a Unit Test? Is it a comprehensive list of test cases which should be analyzed?

A Unit Test is a piece of code that asks a "unit" of your code to perform an operation, then verifies that the operation was indeed performed and the result is as expected. If the result is not correct, it raises / logs an error.

So lets us a say i have a class called "Complex Numbers" with some methods in it (lets says finding conjugate, an overloaded assignment operator and an overloaded multiplication operator. What should be typical test cases for such a class? Is there any methodology for selecting test cases?

Ideally, you would test all the code.

  • when you create an instance of the class, it is created with the correct default values

  • when you ask it to find the conjugates, it does finds the correct ones (also test border cases, like the conjugate for zero)

  • when you assign a value the value is assigned and displayed correctly

  • when you multiply a complex by a value, it is multiplied correctly

Are their any frameworks which can create unit tests for me or i have to write my own class for tests?

See CppUnit

I see an option of "Test" in Visual Studio 2008, but never got it working.

Not sure on that. I haven't used VS 2008 but it may be available just for .NET.

What is the criteria for Units tests? Should there be a unit test for each and every function in a class? Does it make sense to have Unit Tests for each and every class?

Yes, it does. While that is an awful lot of code to write (and maintain with every change) the price is worth paying for large projects: It guarantees that your changes to the code base do what you want them to and nothing else.

Also, when you make a change, you need to update the unit-tests for that change (so that they pass again).

In TDD, you first decide what you want the code to do (say, your complex numbers class), then write the tests that verify those operations, then write the class so that the tests compile and execute correctly (and nothing more).

This ensures that you write the minimal code possible (and don't over-complicate the design of the complex class) and it also ensures that your code does what it does. At the end of writing the code, you have a way to test it's functionality and ensuring it's correctness.

You also have an example of using the code that you will be able to access at any point.

For further reading/documentation, look into "dependency injection" and method stubs as used in unit testing and TDD.

Solution 5

In .NET I strongly recommend "The Art of Unit Testing" by Roy Osherove, it is very comprehensive and full of good advice.

Share:
21,761
Aaron Berry
Author by

Aaron Berry

Updated on April 02, 2020

Comments

  • Aaron Berry
    Aaron Berry about 4 years

    Could anyone suggest books or materials to learn unit test?

    Some people consider codes without unit tests as legacy codes. Nowadays, Test Driven Development is the approach for managing big software projects with ease. I like C++ a lot, I learnt it on my own without any formal education. I never looked into Unit Test before, so feel left out. I think Unit Tests are important and would be helpful in the long run. I would appreciate any help on this topic.

    My main points of concern are:

    1. What is a Unit Test? Is it a comprehensive list of test cases which should be analyzed? So lets us a say i have a class called "Complex Numbers" with some methods in it (lets says finding conjugate, an overloaded assignment operator and an overloaded multiplication operator. What should be typical test cases for such a class? Is there any methodology for selecting test cases?

    2. Are there any frameworks which can create unit tests for me or i have to write my own class for tests? I see an option of "Test" in Visual Studio 2008, but never got it working.

    3. What is the criteria for Units tests? Should there be a unit test for each and every function in a class? Does it make sense to have Unit Tests for each and every class?

  • Georg Fritzsche
    Georg Fritzsche over 14 years
    The google C++ testing framework should also be mentioned: code.google.com/p/googletest
  • Teemu Kurppa
    Teemu Kurppa over 14 years
    +1 gf, googletest (and googlemock) is the best unit testing framework for C++. Amount of overhead when writing tests is about as minimal as it can get in C++. Other frameworks emphasize too much test suites and other irrelevant infrastructure, while googletest focuses on helping to write tests easily.
  • cwash
    cwash over 14 years
    +1. I would say "Test Driven" by Lasse Kossela is a good introduction, more directly in tuned to TDD. There is also a book about "Brownfield Development in .NET" (I think) that may deal with shoehorning tests around existing code - haven't read it, though.