Published on

Googletest Unit Testing in C++ Projects

Authors
  • avatar
    Name
    light-city

Googletest Unit Testing in C++ Projects

Table of Contents

1. Integrating Googletest Unit Testing in CLion

Googletest - Google Testing and Mocking Framework

Source code download link:

https://github.com/google/googletest/releases

Googletest contains two modules, namely gtest and gmock, which need to be compiled separately from source. After compilation, copy the includes folder and .so files to the specified location below.

Then, create an ext directory in the project, divided into two parts:

  • First part: includes

Includes the include files for gmock and gtest, corresponding to the gcc -I parameter, indicating the path to the header files ending with .h.

  • Second part: libs

Contains the libs files for gmock and gtest, corresponding to the gcc -L parameter, indicating the path to the library files containing .so or .dll dynamic or static linking libraries.

├── ext
│   ├── includes
│   │   ├── gmock
│   │   └── gtest
│   └── libs
│       ├── gmock
│       └── gtest

After configuring the above local project path, configure it in CmakeLists.txt:

# ext
set(BASE_INCLUDES ext/includes)
set(BASE_LIBS ext/libs)

# googletest
set(GTEST_INCLUDE_DIR ${BASE_INCLUDES}/gtest/include)
set(GMOCK_INCLUDE_DIR ${BASE_INCLUDES}/gmock/include)
set(GTEST_LINK_DIR ${BASE_LIBS}/gtest/lib/)
set(GMOCK_LINK_DIR ${BASE_LIBS}/gmock/lib/)

# Where to find the header files equivalent to gcc/clang's -I parameter
include_directories(${GTEST_INCLUDE_DIR})
include_directories(${GMOCK_INCLUDE_DIR})

# Where to find the library files .so .dll .dylib equivalent to gcc's -L parameter
link_directories(${GTEST_LINK_DIR})
link_directories(${GMOCK_LINK_DIR})

Then link libraries for each test.

For example, if there is a test file named l1.cpp, configure it in CmakeLists.txt as follows:

add_executable(l1 l1.cpp)
target_link_libraries(l1 gtest gtest_main)  

2. Introduction to Googletest: Hello World

int main(int argc, char* argv[])
{
    // Accept command line arguments
    testing::InitGoogleTest(&argc, argv);
    vector<int> x={1,2,3,5};
    // Using EXPECT_EQ
    for (int i = 0; i < x.size(); ++i)
    {
        EXPECT_EQ(x[i], 1) << "Vectors x and y differ at index " << i;
    }
    RUN_ALL_TESTS();
  
    return 0;
}

For example, the above is a complete example. Every time it runs:

testing::InitGoogleTest(&argc, argv);

And then use:

RUN_ALL_TESTS();

To run all tests, with assertions written for each test.

Let's see the running effect:

l1.cpp:113: Failure
Expected equality of these values:
  x[i]
    Which is: 2
  1
Vectors x and y differ at index 1
l1.cpp:113: Failure
Expected equality of these values:
  x[i]
    Which is: 3
  1
Vectors x and y differ at index 2
l1.cpp:113: Failure
Expected equality of these values:
  x[i]
    Which is: 5
  1
Vectors x and y differ at index 3
[==========] Running 0 tests from 0 test cases.
[==========] 0 tests from 0 test cases ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 0 tests, listed below:

 0 FAILED TESTS

2. Introduction to Googletest Assertions

Regarding assertions, Google has wrapped a series of macros EXPECT and ASSERT, where the difference between the EXPECT series and the ASSERT series is:

  • EXPECT: When failed, the case continues to execute.
  • ASSERT: When failed, it returns directly within the current function, and the statements after ASSERT in the current function will not be executed.

For example:

TEST(ASSERTTest, ASSERT_VS_EXPECT)
{
    ASSERT_TRUE(10<2);  // ASSERT fails, returns directly within the current function, subsequent statements do not execute
    ASSERT_FALSE(10<2);
    EXPECT_EQ(6, Foo(310, 18));
}

Each Test is a macro, the underlying source code for Test is as follows:

# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)

Corresponding to the test case name and the test name.

In the above code, 10<2 is False, and ASSERT_TRUE is used. All content after this Test will not be executed. If changed to EXPECT_TRUE, it will run normally!

Boolean Check

Fatal assertionNonfatal assertionVerifies
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is true
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false

Numeric Data Check

Fatal assertionNonfatal assertionVerifies
ASSERT_EQ(expected, actual);EXPECT_EQ(expected, actual);expected == actual
ASSERT_NE(val1, val2);EXPECT_NE(val1, val2);val1 != val2
ASSERT_LT(val1, val2);EXPECT_LT(val1, val2);val1 < val2
ASSERT_LE(val1, val2);EXPECT_LE(val1, val2);val1 <= val2
ASSERT_GT(val1, val2);EXPECT_GT(val1, val2);

| val1 > val2 | | ASSERT_GE(val1, val2); | EXPECT_GE(val1, val2); | val1 >= val2 |

String Check

TEST(StringCmpTest, Demo)
{
    char* pszCoderZh = "CoderZh";
    wchar_t* wszCoderZh = L"CoderZh";
    std::string strCoderZh = "CoderZh";
    std::wstring wstrCoderZh = L"CoderZh";

    EXPECT_STREQ("CoderZh", pszCoderZh);
    EXPECT_STREQ(L"CoderZh", wszCoderZh);

    EXPECT_STRNE("CnBlogs", pszCoderZh);
    EXPECT_STRNE(L"CnBlogs", wszCoderZh);

    EXPECT_STRCASEEQ("coderzh", pszCoderZh);
    //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh);    Not supported

    EXPECT_STREQ("CoderZh", strCoderZh.c_str());
    EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str());
}

Where STREQ and STRNE support both char* and wchar_t* types, STRCASEEQ and STRCASENE only accept char*.

Display Success or Failure

To directly return success: SUCCEED();

To return failure:

Fatal assertionNonfatal assertion
FAIL();ADD_FAILURE();
// Return success or failure
TEST(ExplicitTest, Demo)
{
    ADD_FAILURE() << "This line fails Sorry"; // None Fatal Asserton,continues execution.

    //FAIL(); // Fatal Assertion,does not execute the following statements in this test case.
    EXPECT_TRUE(1==2)<<"1==2 failed!";      // To verify whether the statements after failure are executed

    SUCCEED();
}

Exception Check

There are three types:

EXPECT_NO_THROW(statement);: No exception thrown.

EXPECT_ANY_THROW(statement);: Any type of exception thrown.

EXPECT_THROW(statement, exception_type);: Specific type of exception thrown.

TEST(ExceptionTest,et) {
    // Any type of exception thrown
    EXPECT_ANY_THROW(10/0); //Expected: 10/0 throws an exception.
    // Specific type of exception thrown
    EXPECT_THROW(1/0,int); //Expected: 1/0 throws an exception of type int.
}

Predicate Assertions

When checking whether a function returns TRUE or FALSE, it is useful to output the parameters passed in, to facilitate tracking in case of failure.

For example:

// Predicate Assertion
bool MN(int m, int n)
{
    return m>n;
}
// When checking whether a function returns TRUE or FALSE, it is useful to output the parameters passed in, to facilitate tracking in case of failure.
TEST(PredicateAssertionTest, Demo)
{
    int m = 5, n = 6;
    EXPECT_PRED2(MN, m, n); //Provide only <= 5 parameters, parameters should correspond to the MN function
}

EXPECT_PRED2(pred2, val1, val2); is similar to ASSERT. PRED2 can go up to PRED5.

Supports up to 5 parameters.

Floating-Point Check

EXPECT_FLOAT_EQ(expected, actual) and EXPECT_DOUBLE_EQ(expected, actual)

Similar to ASSERT.

For comparing two close numbers:

EXPECT_NEAR(val1, val2, abs_error);

Similar to ASSERT.

For example:

// Floating-Point
TEST(FloatDoubleTest,Demo) {
    ASSERT_DOUBLE_EQ(1.1,1.1);
    EXPECT_FLOAT_EQ(1.2,4.0);
    EXPECT_NEAR(1.234,1.888,0.9);
//    EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2);
//    EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
    EXPECT_PRED_FORMAT2(testing::FloatLE,1,0);      // LE means less than or equal to, i.e., value1 <= value2
    EXPECT_PRED_FORMAT2(testing::DoubleLE,0.1,0.2);
}

Type Check

// Type Check
template <typename T>
class Tt{
public:
    void foo() {
        testing::StaticAssertTypeEq<bool, T>();     // No error if consistent with the call below, otherwise error
    }
};
TEST(TypeAssertionTest, Demo)
{
    Tt<bool> tt;
    tt.foo();
}

Learning reference from: https://www.cnblogs.com/coderzh/archive/2009/04/06/1430364.html