The above answers were helpful, but I wanted to share a solution I am using that keeps each test short while still testing both the exception type and the 'what' value. It works for any function that throws an exception that is derived from std::exception, but could be modified (or templated) to catch other types if needed.
I originally tried using a perfect forwarding type wrapper function, but ended up just using a lambda as a wrapper. Using a lambda is really flexible for re-use, allows all the expected implicit type conversions that happen when calling functions directly, avoids passing pointer-to-member functions, etc..
The important point is to have the wrapper template function throw a custom exception for a 'what-mismatch' that has a type that would not be thrown from the function being tested. This causes EXPECT_THROW to print a nice error about the mismatch. I derived from std::runtime_error since that class has a constructor that accepts a std::string.
class WhatMismatch : public std::runtime_error {
public:
WhatMismatch(const std::string& expectedWhat, const std::exception& e)
: std::runtime_error(std::string("expected: '") + expectedWhat +
"', actual: '" + e.what() + '\'') {}
};
template<typename F> auto call(const F& f, const std::string& expectedWhat) {
try {
return f();
} catch (const std::exception& e) {
if (expectedWhat != e.what()) throw WhatMismatch(expectedWhat, e);
throw;
}
}
A test for a function foo that should throw a std::domain_error would look like:
EXPECT_THROW(call([] { foo(); }, "some error message"), std::domain_error);
If the function takes parameters, just capture them in the lambda like this:
EXPECT_THROW(call([p1] { foo(p1); }, "some error message"), std::domain_error);