Requirement changes will be introduced in the future.
Frequently touched regions are at greater risk of unintended changes in behavior.
Critical regions of code should be thoroughly tested to avoid encountering bugs when using them.
Unit testing each class or free function increases code coverage and reduces odds of overlooked bugs.
Generally, only test public methods in a class.
Consider all paths a function can branch to and make sure to test each branching condition.
Arrange
: Set up and prepare the state of the test.
Act
: Call the function.
Assert
: Test the outcome or new state of the instance under test.
Consider we want to test the following function.
1
2
template <typename T, std::enable_if_t<!std::is_integral_v<T>, bool> = true>
double translate(T num);
1
2
3
TEST(MathTests, CanTranslate) {
EXPECT_EQ(translate(4.32), 23.4);
}
1
2
3
4
5
6
7
8
9
10
11
TEST(MathTests, CanTranslate) {
// Arrange
constexpr auto input{ 4.32 };
constexpr auto expected_output{ 23.4 };
// Act
const auto actual_output{ translate(input) };
// Assert
EXPECT_EQ(expected_input, actual_output);
}
Testing a class with dependencies.
1
2
3
4
5
6
7
8
9
10
class MyClass {
public:
MyClass(IDependencyA* depA, IDependencyB* depB)
: m_dependencyA(depA), m_dependencyB(depB) {}
int run();
private:
IDependencyA* m_dependencyA = nullptr;
IDependencyB* m_dependencyB = nullptr;
};
1
2
3
4
5
6
7
8
9
10
11
12
class MyClassTests : public Test {
protected:
MyClassTests() {
m_depA = std::make_unique<NiceMock<MockDependencyA>>();
m_depB = std::make_unique<NiceMock<MockDependencyB>>();
m_classUnderTest = MyClass(m_depA.get(), m_depB.get());
}
std::unique_ptr<MockDependencyA> m_depA;
std::unique_ptr<MockDependencyB> m_depB;
MyClass m_classUnderTest;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TEST_F(MyClassTests, RunCallsDependencyAAndB) {
// Arrange
constexpr auto expected_output{ 1 };
EXPECT_CALL(*m_depA, get(_)).WillOnce(
Return(std:string())
);
EXPECT_EQ(*m_depB, create(_)).WillOnce(
Return(std::string())
);
// Act
const auto actual_output{ m_classUnderTest.run() };
// Assert
EXPECT_EQ(actual_output, expected_output);
}
Ex. Connecting to a database is required to continue.
1
2
3
4
5
6
7
8
9
10
11
// Arrange
MyClass myClass;
ASSERT_TRUE(myClass.connectDB()); // If cannot establish connection, cannot test code
// Act
const auto actual{ myClass.sendRequest() };
// Assert
EXPECT_EQ(actual.value, "Expected");
EXPECT_EQ(actual.primaryKey, "Primary Key");
EXPECT_EQ(actual.name, "Name");
Ex. Requiring a container is a specific size.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Arrange
MyClass myClass;
// Act
const auto actual{ myClass.sendRequest() };
// Assert
ASSERT_EQ(actual.container.size(), 4); // End test if size is not 4.
EXPECT_EQ(actual.container.at(0), "Value 1");
EXPECT_EQ(actual.container.at(1), "Value 2");
EXPECT_EQ(actual.container.at(2), "Value 3");
EXPECT_EQ(actual.container.at(3), "Value 4");
EXPECT_EQ(val1, val2)
Asserts that val1
is equal to val2
.
EXPECT_NE(val1, val2)
Asserts that val1
is not equal to val2
.
EXPECT_LT(val1, val2)
Asserts that val1
is less than val2
.
EXPECT_LE(val1, val2)
Asserts that val1
is less than or equal to val2
.
EXPECT_GT(val1, val2)
Asserts that val1
is greater than val2
.
EXPECT_GE(val1, val2)
Asserts that val1
is greater than or equal to val2
.
EXPECT_TRUE(condition)
Asserts that condition
is true.
EXPECT_FALSE(condition)
Asserts that condition
is false.
EXPECT_NEAR(val1, val2, abs_error)
val1
is within a certain absolute error (abs_error
) of val2
.1
EXPECT_NEAR(20.123456, 20.123000, 1e-3);
The above code evaluates to true (only compares to the thousandths position).
EXPECT_THROW(statement, exception_type)
Asserts that statement
throws an exception of type exception_type
.
EXPECT_ANY_THROW(statement)
Asserts that statement
throws an exception of any type.
EXPECT_NO_THROW(statement)
Asserts that statement
does not throw any exceptions.
GTest displays error values very well:
1
2
3
4
5
Expected equality of these values:
x
Which is: 5
y
Which is: 10
You can return custom messages on failure:
1
2
3
EXPECT_TRUE(<false_condition>) <<
"Expected " << <true_condition> <<
"but instead got " << <false_condition> << '.';
TEST(TestSuiteName, TestName)
Global tests are great for free functions or very specific tests.
TEST_F(TestFixtureName, TestName)
Test fixtures are great for classes that need slightly more setup and teardown.
TEST_P(TestFixtureName, TestName)
Parametric tests are great for methods or functions with a wide range of potential input parameters.