Unit Test Framework – Is It Really Necessary?

language-agnosticunit testing

Currently at my job, we have a large suite of unit tests for our C++ application. However we don't use a unit test framework. They simply utilize a C macro that basically wraps an assert and a cout. Something like:

VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}

Then we simply create functions for each of our tests like

void CheckBehaviorYWhenXHappens()
{
    // a bunch of code to run the test
    //
    VERIFY(blah != blah2);
    // more VERIFY's as needed
}

Our CI server picks up "unit test failed" and fails the build, emailing the message to the developers.

And if we have duplicate setup code, we simply refactor it like we would any other duplicated code we'd have in production. We wrap it behind helper functions, make some test classes wrap setting up frequently used scenarios.

I know there's frameworks out there like CppUnit and boost unit test. I'm wondering what value do these add? Am I missing what these bring to the table? Is there something useful I could gain from them? I'm hesitant to add a dependency unless it adds real value especially since it seems what we have is dead simple and works well.

Best Answer

As others have already said, you already have your own, simple, home made framework.

It seems to be trivial to make one. However, there are some other features of a unit-test framework that are not so easy to implement, because they take some advanced knowledge of the language. The features I generally require from a test framework and are not so easy to homebrew are:

  • Automatic collection of test cases. I.e. defining new test method should be enough to get it executed. JUnit automatically collects all methods whose names start with test, NUnit has the [Test] annotation, Boost.Test uses the BOOST_AUTO_TEST_CASE and BOOST_FIXTURE_TEST_CASE macros.

    It's mostly convenience, but every bit of convenience you can get improves the chance developers will actually write the tests they should and that they will connect them in correctly. If you have long instructions, somebody will miss part of them now and than and perhaps some tests won't be running and nobody will notice.

  • Ability to run selected test cases, without tweaking code and recompiling. Any decent unit-test framework allows you to specify which tests you want to run on command-line. If you want to debug on unit tests (it's most important point in them for many developers), you need to be able to select just some to run, without tweaking code all over the place.

    Say you just received bug report #4211 and it can be reproduced with unit test. So you write one, but than you need to tell the runner to run just that test, so you can debug what's actually wrong there.

  • Ability to mark tests expected failures, per test case, without modifying the checks themselves. We actually switched frameworks at work to get this one.

    Any decently sized test suite will have tests, that are failing because the features they test were not implemented yet, were not finished yet, nobody had time to fix them yet or something. Without ability to mark tests as expected failures, you won't notice another failure when there are some regularly, so the tests stop serving their main purpose.

Related Topic