dutt
dutt

Reputation: 8209

Exceptions and BDD in C++ - Catch library

I've been using Boost.Test so far but am now looking into using BDD with Catch instead, but I have some trouble figuring out a nice way of handling exceptions. Say I've got a test like this:

SCENARIO("connection handling", "[network]") {
    boost::asio::io_service io;
    GIVEN("a connection that should fail") {
        connection::ptr conn = connection::create(new fake_provider<connection_refused>(io));
        WHEN("trying to connect") {
            conn->connect("localhost", 1);
            THEN("connection was refused") {
                some stuff to verify exception code
                REQUIRE(conn->connected() == false);
            }
        }
    }
}

Now I'm wondering how to handle the fact that connect() will throw an exception in a nice way. I figure I could save and store the exception in a try-catch and verify under THEN, but that doesn't seem very nice. In my Boost.Test testcases I did this:

bool error_is_connection_refused(boost::system::system_error ex) {
    return ex.code() == boost::system::errc::connection_refused;
}
BOOST_AUTO_TEST_CASE(connect)
{
    connection::ptr conn_refuse = connection::create(new fake_provider<connection_refused>(*io_ptr));
    BOOST_REQUIRE_EXCEPTION(conn_refuse->connect("localhost", 1),
                            boost::system::system_error,
                            error_is_connection_refused);
    BOOST_REQUIRE_EQUAL(conn_refuse->connected(), false);
}

But that doesn't seem very BDD. How do people usually handle exception throwing code when using BDD testing?

Upvotes: 2

Views: 1291

Answers (2)

iutinvg
iutinvg

Reputation: 4235

This is how to verify exception content as suggested by philsquared

#include <stdexcept>
#include "catch.hpp"

void my_func(double v) 
{
    // ...
}

TEST_CASE("wrong params", "[tag]") {
    SECTION("wrong rate") {
        try {
            my_func(1.1);  // must be in range [0..1]
            REQUIRE_FALSE("must raise issue about rate");
        }
        catch(const std::invalid_argument& e) {
            std::string str (e.what());
            std::string str2 ("rate");
            REQUIRE_FALSE(str.find(str2) == std::string::npos);
        }
    }
}

Upvotes: 0

philsquared
philsquared

Reputation: 22493

I'm a bit late to this as I've only just noticed the catch-unit-test tag :-)

Currently you can do:

REQUIRE_THROWS( <expr> );

or to test for a specific exception type:

REQUIRE_THROWS_AS( <type>, <expr> );

If you want to verify the contents of the exception message... there's not currently a way to do that without catching it yourself. That's a feature I've considered adding, though.

Upvotes: 6

Related Questions