Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Exception correctness
PrevUpHomeNext

Any unexpected/uncaught exception raised in the test case body will be intercepted by the Boost.test framework and will result in the termination of the test-case with the status failed.

Example: Uncaught exception

Code

#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>

struct my_struct {
  my_struct(int var_) : var(var_)
  {
    if(var_ < 0) throw std::runtime_error("negative value not allowed");
  }
  int var;
};

BOOST_AUTO_TEST_CASE( test )
{
  my_struct instance(-2);
  // ...
}

BOOST_AUTO_TEST_CASE( test2 )
{
  BOOST_TEST(true);
}

Output

> example --log_level=all
Running 2 test cases...
Entering test module "example"
test.cpp:20: Entering test case "test"
unknown location:0: fatal error: in "test": std::runtime_error: negative value not allowed
test.cpp:20: last checkpoint: "test" entry.
test.cpp:20: Leaving test case "test"; testing time: 247us
test.cpp:26: Entering test case "test2"
test.cpp:28: info: check true has passed
test.cpp:26: Leaving test case "test2"; testing time: 103us
Leaving test module "example"; testing time: 492us

*** 1 failure is detected in the test module "example"

More control over the exception correctness is often required, for instance to test that an expression is raising a specific exception, intentionally.

The Unit Test Framework provides several assertions for testing a code with respect to the exceptions correctness. The following assertions are available:

  • BOOST_<level>_NO_THROW checks that no exception is raised from an expression,
  • BOOST_<level>_THROW checks that an expression raises an exception of a specific type
  • BOOST_<level>_EXCEPTION checks that an expression raises an exception of a specific type, a passes the exception instance to a predicate function for further validation (introspection for instance)

The following example demonstrate how to use these tools to test the correct behavior of the API of FileWordHistogram, in the constructor and the preconditions of the member function.

Example: Exception correctness of an API

Code

#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>
#include <stdexcept>
#include <fstream>

//! Computes the histogram of the words in a text file
class FileWordHistogram
{
public:
  //!@throw std::exception if the file does not exist
  FileWordHistogram(std::string filename) : is_processed(false), fileStream_(filename) {
    if(!fileStream_.is_open()) throw std::runtime_error("Cannot open the file");
  }

  //! @returns true on success, false otherwise
  bool process() {
    if(!is_processed) return true;

    // ...
    is_processed = true;
    return true;
  }

  //!@pre process has been called with status success
  //!@throw std::logic_error if preconditions not met
  std::map<std::string, std::size_t>
  result() const {
    if(!is_processed)
      throw std::runtime_error("\"process\" has not been called or was not successful");
    return histogram;
  }

private:
  bool is_processed;
  std::ifstream fileStream_;
  std::map<std::string, std::size_t> histogram;
};

BOOST_AUTO_TEST_CASE( test_throw_behaviour )
{
  // __FILE__ is accessible, no exception expected
  BOOST_REQUIRE_NO_THROW( FileWordHistogram(__FILE__) );

  // ".. __FILE__" does not exist, API says std::exception, and implementation
  // raises std::runtime_error child of std::exception
  BOOST_CHECK_THROW( FileWordHistogram(".." __FILE__), std::exception );

  {
    FileWordHistogram instance(__FILE__);

    // api says "std::logic_error", implementation is wrong.
    // std::runtime_error not a child of std::logic_error, not intercepted
    // here.
    BOOST_CHECK_THROW(instance.result(), std::logic_error);
  }
}

Output

> example --log_level=all
Running 1 test case...
Entering test module "example"
test.cpp:47: Entering test case "test_throw_behaviour"
test.cpp:50: info: check 'no exceptions thrown by FileWordHistogram("test")' has passed
test.cpp:54: info: check 'exception std::exception is caught' has passed
unknown location:0: fatal error: in "test_throw_behaviour": std::runtime_error: "process" has not been called or was not successful
test.cpp:62: last checkpoint
test.cpp:47: Leaving test case "test_throw_behaviour"; testing time: 533us
Leaving test module "example"; testing time: 643us

*** 1 failure is detected in the test module "example"
[Note] Note

An assert(...) might call abort(): the use of the macros above may not be suitable for testing for assert's in a portable manner.

Bibliographic references

Publications

Exceptions and Error Handling

Standard C++ Foundation


PrevUpHomeNext