ForeverLearning
ForeverLearning

Reputation: 6675

Verifying exception messages with GoogleTest

Is it possible to verify the message thrown by an exception? Currently one can do:

ASSERT_THROW(statement, exception_type)

which is all fine and good but no where can I find a way to test e.what() is really what I am looking for. Is this not possible via google test?

Upvotes: 11

Views: 11909

Answers (2)

A.E. Drew
A.E. Drew

Reputation: 2137

Something like the following will work. Just catch the exception somehow and then do EXPECT_STREQ on the what() call:

#include "gtest/gtest.h"

#include <exception>

class myexception: public std::exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex;


TEST(except, what)
{
  try {
    throw myex;
    FAIL();  // exception not thrown as expected
  } catch (std::exception& ex) {
      EXPECT_STREQ("My exception happened", ex.what());
  }

}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Upvotes: 4

Florian Winter
Florian Winter

Reputation: 5279

You can build your own assertion that allows you to make assertions on the thrown expected exception:

  1. In a helper function, catch the exception, make assertions about it, then re-throw it.
  2. In an assertion function, call the helper function wrapped in EXPECT_THROW.
template<typename ExceptionT, typename ActionF, typename ExceptionMatcher>
void ExpectThrowThatHelper(ActionF action, ExceptionMatcher&& exceptionMatcher)
{
    try
    {
        action();
    }
    catch (const ExceptionT& e)
    {
        EXPECT_THAT(e, std::forward<ExceptionMatcher>(exceptionMatcher));
        throw;
    }
}

template<typename ExceptionT, typename ActionF, typename ExceptionMatcher>
void ExpectThrowThat(ActionF action, ExceptionMatcher&& exceptionMatcher)
{
    EXPECT_THROW(ExpectThrowThatHelper<ExceptionT>(std::forward<ActionF>(action), std::forward<ExceptionMatcher>(exceptionMatcher)), ExceptionT);
}

This approach applies a matcher to the exception using EXPECT_THAT. You could also just pass a function and call it, but since matchers can be built from lambdas, I find it more elegant to support matchers.

You can use this directly as follows:

struct GivenException final : std::exception
{
    int Value = 0;

    explicit GivenException(const int value)
        : Value(value)
    {}

    [[nodiscard]] const char* what() const noexcept override
    {
        return "GivenException";
    }
};

TEST(ExceptionInspectionTest, SomeCode_ThrowsGivenExceptionWithSpecificValue)
{
    using testing::Field;
    using testing::Eq;

    ExpectThrowThat<GivenException>([]
        {
            throw GivenException(123);
        }, Field(&GivenException::Value, Eq(123)));
}

If you like preprocessor macros:

#define EXPECT_THROW_THAT(ACTION, EXCEPTION, MATCHER) (ExpectThrowThat<EXCEPTION>([]{ACTION;}, (MATCHER)))

TEST(ExceptionInspectionTest, SomeCode_ThrowsGivenExceptionWithSpecificValue)
{
    using testing::Field;
    using testing::Eq;

    EXPECT_THROW_THAT(throw GivenException(123), GivenException, Field(&GivenException::Value, Eq(123)));
}

Likewise, you can write ASSERT_THROW_THAT, which uses ASSERT_THROW and ASSERT_THAT.

Upvotes: 0

Related Questions