GoogleTest
Introduction
-
Test Suite: Group of one or more tests. When multiple tests in a test suite need to share common objects and subroutines, you can put them into a test fixture class.
-
Test: Exercise a particular program path with specific input values and verify the results
-
Test Fixture: Contain multiple tests that need to share common objects and subroutines.
Assertions: Statements that check whether a condition is true (Assertion Reference here).
- Result can be success, nonfatal or fatal failure.
- If fatal, aborts the function being tested.
Assertion are macros that can have different effects on the function:
ASSERT_*
: Generates fatal failures and abort the current function.EXPECT_*
: Generates nonfatal failures which do not abort the current function.
To show a custom failure message, it is possible to stream it to an assertion:
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
For the complete list of assertions provided by GoogleTest, see the Assertions Reference.
Creating a test
- Use the
TEST()
macro to define and name a test function that does not return a value. - Along with valid C++ statements, use assertions to check values
-
Results are determined by assertions.
TEST(TestSuiteName, TestName) { --> Names should be valid C++ identifiers ... test body ... and not contain underscores (_) } --> Same TestSuiteName tests are grouped (they belong to the same test suite)
Example:
int Factorial(int n); // Returns the factorial of n
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(Factorial(0), 1);
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(Factorial(1), 1);
EXPECT_EQ(Factorial(2), 2);
EXPECT_EQ(Factorial(3), 6);
EXPECT_EQ(Factorial(8), 40320);
}
Test Fixtures (link)
A test fixture allows for multiple tests that use the same configurations to reuse that configuration code:
#include <gtest/gtest.h>
class SampleTest : public ::testing::Test {
protected: <-- protected since the members are accessed via sub-classes
void SetUp() override {
std::cout << "Test up\n"; <-- I added this but standard output might not be always visible
// Code here will be executed immediately before each TEST_F
}
void TearDown() override {
std::cout << "Test down\n"; <-- I added this but standard output might not be always visible
// Code here will be executed immediately after each TEST_F
}
// Define your test object here, such as:
int testVariable = 10;
};
TEST_F(SampleTest, TestName) { <-- Must be a TEST_F (_F stands for "fixture")
// Access your test object (allows access to objects and subroutines)
EXPECT_EQ(testVariable, 10); First argument must be name of fixture class
// Other test code...
}
In this case, TestName is based on the SampleTest test fixture class and uses the SetUp and TearDown methods from it. Sometimes, the constructor/destructor of the test fixture should be used instead of SetUp/TearDown (see more here).
Running tests
After defining your tests, you can run them with RUN_ALL_TESTS()
, which returns 0 if all the tests are successful, or 1 otherwise. Note that RUN_ALL_TESTS()
runs all tests in your link unit–they can be from different test suites, or even different source files.
gMock
gMock is a library or “framework” for creating mock classes for C++ that is included with googleTest.
A mock object implements the same interface as a real object (to be used instead) AND specify at runtime how it will be used and called (which methods, arguments, how many times, etc).
There is a difference between fake objects and mock objects:
- Fake objects have “cheap” working implementations which are not suitable for production
- Mocks are pre-programmed with expectations, which form the specification for what is expected.
Creating a Mock Class
- Derive a class
MockTurtle
fromTurtle
- Take a virtual function of Turtle (gMock overrites the function from a base class with a virtual function automatically)
- In
public:
section, writeMOCK_METHOD()
- Take the function signature (inputs, outputs and name of function) and paste it into the macro with commas separating the fields
- If mocking a const method, add a forth parameter
(const)
- If mocking a const method, add a forth parameter
- Since the virtual method is being overriding, it is suggested to add the
override
keyword:(const, override)
-
Do step 2 to 5 for every virtual function being mocked
#include <gmock/gmock.h> // Brings in gMock. class MockTurtle : public Turtle { // #1 & #2 public: // #3 ... MOCK_METHOD(void, PenUp, (), (override)); // #4 & #5 MOCK_METHOD(void, PenDown, (), (override)); MOCK_METHOD(void, Forward, (int distance), (override)); MOCK_METHOD(void, Turn, (int degrees), (override)); MOCK_METHOD(void, GoTo, (int x, int y), (override)); MOCK_METHOD(int, GetX, (), (const, override)); MOCK_METHOD(int, GetY, (), (const, override)); };
Using the mocks in tests
- Import the gMock names from the
testing
namespace (namespaces are a good idea) - Create some mock objects
- Specify expectations (how many times will it be called, what arguments, etc.)
- Write code that uses the mocks
- Optionally, check results with googletest assertions (if mock is called more than expected or with wrong arguments)
-
When a mock is destroyed, gMock will check if expectations have been satisfied
#include "path/to/mock-turtle.h" #include <gmock/gmock.h> #include <gtest/gtest.h> using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); // #5 }
Setting Expectations
The right expectations must be set for the test to be evaluated correctly and not fail as result of unrelated changes. In gMock the EXPECT_cALL()
is used to set an expectation on a mock method. The cardinality options can be seen here:
using ::testing::Return;
...
EXPECT_CALL(turtle_object, GetX(matchers)) // Two arguments: the mock object and the method and its arguments
.Times(5) // Method will be called 5 times (cardinality),
.WillOnce(Return(100)) // it will return 100 one time (the first time),
.WillOnce(Return(150)) // it will return 150 the second time
.WillRepeatedly(Return(200)); // and then return 200 the remaining times.
Another examples:
-
Specifying expected arguments:
These can work by setting any generic comparison, as seen here.
// Expects the turtle to move forward by 100 units. (Equivalent to Eq(100)) EXPECT_CALL(turtle, Forward( 100 ) ); // Expects the turtle moves forward by at least 100 units. EXPECT_CALL(turtle, Forward( Ge(100) ) );
-
Not interested in the value of certain arguments:
For this, the
_
can be used in place of an argument, meaning “anything goes” (Wildcard). The_
is called a matcher and can be used insideEXPECT_CALL()
.using ::testing::_; ... // Expects that the turtle jumps to somewhere on the x=50 line. EXPECT_CALL(turtle, GoTo( 50, _ ) );