GTest
- Tags
- library
Is the standard testing framework for CPP provided by Google.
Tests
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace ::testing;
template <class T>
T square(T i) { return i * i; }
// You declare a test case with the TEST macro.
//
// The first argument is the namespace/scope of the test case
// and the second argument is the test name.
TEST(Square, testThatRegularInputGivesCorrectAnswer) {
// You can stream values into assertions to provide more debug output.
EXPECT_THAT(square(4.0), Eq(16.0)) << "Did not square correctly";
}
Fixtures
Fixtures in GTest are unlike ones you may have grown accustomed to in Python. In
GTest a fixture is a class which is initialised with the test case, or a suite of
test cases related to that fixture, and whose protected members can be accessed
from within the test case.
All fixtures in GTest must inherit from testing::test
.
class MyFixture {
protected:
void SetUp() override {
testNum = 5;
testValue = 25;
}
double testNum;
double testValue;
};
// Tests using a fixture use TEST_F and take the fixture class as,
// the namespace argument.
TEST_F(MyFixture, squareWorksWithMyFixtureValues) {
// We can implicitly access protected members in the test case.
EXPECT_THAT(square(testNum), EQ(testValue));
}
You should use fixtures to initialise some state (such as a queue or database) that your test cases will reuse. You can also use it as a way to test non-public methods of a class by making those methods public and having the fixture inherit from the class as well.
Parameterised Tests
Work similar to fixtures for GTest.
We define a test deriving from testing::TestWithParam<T>
or including the
testing::WithParamInterface<T>
mixin.
std::string frobulate(const string &foo) { return foo + " frob"; }
typedef std::pair<std::string, std::string> FooParam;
class FooFixture : TestWithParam<FooParam> {};
// Declare a parametrised test case using FooFixture.
TEST_P(FooFixture, frobulates) {
std::string foo = GetParam().first;
std::string expected = GetParam().second;
EXPECT_THAT(frobulate(foo), EQ(expected));
}
// Instantiate all test cases using FooFixture in the Foo namespace
// with 2 parameter sets.
INSTANTIATE_TEST_CASE_P(Foo, FooFixture,
Values(FooParam("foo", "foo frob"),
FooParam("bar", "bar frob")));
Mocking
GTest exposes mocking through the GMock library.
class Foo {
public:
virtual void foo(int fob);
};
class MockFoo : public Foo {
public:
// Note: The following must be in the public section, even though
// the methods may be protected or private in the base class.
MOCK_METHOD1(foo, void(int));
// gmock provides numerous similair macros for mocking functions
// with different types. MOCK_METHOD0 takes no arguments, MOCK_METHOD1
// takes 1 argument etc. If the method being mocked is suffixed by const
// meaning it doesn't modify the object you can use MOCK_CONST_METHOD1.
};
TEST(Foo, fooTest) {
MockFoo my_foo;
// Declare that method foo on object my_foo will be called 3 at least twice
// in this test. Make it return 0 the first time, 1 the second time and for
// any calls beyond that return 2.
EXPECT_CALL(my_foo, foo(_))
.Times(AtLeast(2))
.WillOnce(Return(0))
.WillOnce(Return(1))
.WillRepeatedly(Return(2));
// Some logic that causes foo to be called.
// ...
}
Warn: To mock a method with GMock you must declare that method as virtual in the original class. This is to ensure method resolution when using references of the parent class use the implementation in the mocked class.
Wildcards and Deactivating a Mock
When mocking a method you can filter the responses based on the arguments.
TEST(Foo, fooTest) {
MockFoo my_foo;
EXPECT_CALL(my_foo, foo("google.com"))
.WillRepeatedly(Return(2));
EXPECT_CALL(my_foo, foo("apple.com"))
.WillRepeatedly(Return(3));
my_foo.foo("google.com"); //=> 2
my_foo.foo("apple.com"); //=> 3
my_foo.foo("apple.com"); //=> 3
my_foo.foo("google.com"); //=> 2
}
The way this works is that every time we do an EXPECT_CALL
GMock will push the
configuration into a stack. Then when a later call to the mocked method comes in
it looks through all the entries on the stack (LIFO obviously) until it matches
the parameter list and then returns the correct value.
To simplify this the wildcard parameter _
can be given and will always match any
argument passed for that parameter.
Note: This could have unintended affect where one wildcard is so generic it
always matches the arguments, when you only wanted it to match until it is
saturated (has been used up the expected number of times). To fix this you can
use RetiresOnSaturation
.
TEST(Foo, fooTest) {
MockFoo my_foo;
EXPECT_CALL(my_foo, foo("google.com"))
.WillRepeatedly(Return(2));
EXPECT_CALL(my_foo, foo(_))
.Times(2)
.WillRepeatedly(Return(3))
.RetiresOnSaturation();
my_foo.foo("google.com"); //=> 2
my_foo.foo("google.com"); //=> 2
my_foo.foo("google.com"); //=> 3
}
Default Return Values
Matchers
Are how GTest performs an assertion. They compare one value with another and produce semantically relevant output if the comparison fails. GTest comes with numerous built in matchers and some macros to simplify them.
You can find a comprehensive list of available matchers here.
Note: In some cases GTest provides a helper macro to simplify common matchings.
For example EXPECT_EQ(foo, bar) == EXPECT_THAT(foo, EQ(bar))
.
EXPECT vs ASSERT
GTest actually provides 2 assertion macros.
EXPECT
performs an assertion and fails the test if the assertion fails, but doesn't
terminate the execution of the test. The test case can continue to perform other
expectations until it's terminated. ASSERT
immediately terminates a test case when
an assertion fails. This is to avoid triggering undefined behaviour.
Use ASSERT
whenever the remaining tests in the test case requires the current
assertion to be true, otherwise use EXPECT
. For example if the rest of the tests in
a test case require a file to be successfully opened, it makes little sense to
perform those assertions if the file failed to be opened.