Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Testing with Exceptions

When we're testing a system, we want to test the failure cases as well as the success cases. This means forcing the system under test down an error path by orchestrating bad inputs or synthesizing errors from code collaborating with the system under test.

Let's add the requirement that hello_world should throw the a std::runtime_error exception if the supplied stream has the badbit set on the stream.

We can add a test case for this:

BOOST_AUTO_TEST_CASE(hello_world_stream_with_badbit_throws_runtime_error)
{
    std::ostringstream dest;
    dest.clear(std::ios_base::badbit);

    hello_world(dest);

    BOOST_FAIL("std::runtime_error not thrown");
}

[Note] Note

The clear member function on a stream clears all state bits and sets the state to the value of the argument.

Instead of an assertion macro like BOOST_REQUIRE_EQUAL, we're using the BOOST_FAIL macro that guarantees test failure. If the call to hello_world doesn't throw a runtime_error exception and continues to the next line of code, then this test case fails:

Running 2 test cases...
src/tutorials/testing_with_exceptions/1/test/test_hello.cpp(24): fatal error in "hello_world_stream_with_badbit_throws_runtime_error": std::runtime_error not thrown

*** 1 failure detected in test suite "Master Test Suite"

EXIT STATUS: 201

Now let's enhance the implementation to support this requirement:

void hello_world(std::ostream& stream)
{
    if (stream.bad())
    {
        throw std::runtime_error("bad stream");
    }
    stream << "Hello, world!\n";
}

We run our test and get something similar to the following:

Running 2 test cases...
unknown location(0): fatal error in "hello_world_stream_with_badbit_throws_runtime_error": std::runtime_error: bad stream
src/tutorials/testing_with_exceptions/2/test/test_hello.cpp(13): last checkpoint

*** 1 failure detected in test suite "Master Test Suite"

EXIT STATUS: 201

Now the test is still failing, so what did we do wrong? The exception from our system under test unwound the call stack back into the unit test framework, which caught the exception and reported this as a failure. We need to tell the test framework that an exception is expected in this situation. We can use BOOST_REQUIRE_THROW to tell the test framework that an expression is expected to throw a particular type of exception. If the exception isn't thrown or an exception of a different type is thrown, then the test fails. Our test now looks like this:

BOOST_AUTO_TEST_CASE(hello_world_stream_with_badbit_throws_runtime_error)
{
    std::ostringstream dest;
    dest.clear(std::ios_base::badbit);

    BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error);
}

Now our test case is passing:

Running 2 test cases...

*** No errors detected

EXIT STATUS: 0
Some Observations
Example Source Code

PrevUpHomeNext