【C++】Google Test(gtest)单元测试_测试_断言
gtest是Google公司发布的一款开源的C/C++单元测试框架。gtest的TEST 宏用于定义单个测试用例,其基本语法为:
TEST(TestCaseName, TestName) { // 测试代码}
个中 TestCaseName为测试用例的名称,用于将干系的测试分组在一起,以便在测试结果中更随意马虎地识别和归类。TestName为详细测试的名称,一样平常描述测试的目的。
每个测试用例包含一个或多个检讨点,这些检讨点利用断言来验证代码的行为。包括以EXPECT_ 为前缀的非致命断言,其在测试失落败时程序会连续实行;和以 ASSERT_ 味前缀的致命断言,其在测试失落败时程序立即终止。基本的非致命断言包括:
EXPECT_EQ(val1, val2):检讨 val1 == val2EXPECT_NE(val1, val2):检讨 val1 != val2EXPECT_LT(val1, val2):检讨 val1 < val2EXPECT_LE(val1, val2):检讨 val1 <= val2EXPECT_GT(val1, val2):检讨 val1 > val2EXPECT_GE(val1, val2):检讨 val1 >= val2对应的致命断言:
ASSERT_EQ(val1, val2)ASSERT_NE(val1, val2)ASSERT_LT(val1, val2)ASSERT_LE(val1, val2)ASSERT_GT(val1, val2)ASSERT_GE(val1, val2)除此之外,还有专门用于字符串比较的断言:
EXPECT_STREQ(str1, str2):检讨 str1 和 str2 是相同的字符串。EXPECT_STRNE(str1, str2):检讨 str1 和 str2 是不同的字符串。EXPECT_STRCASEEQ(str1, str2):检讨 str1 和 str2 是相同的字符串,忽略大小写。EXPECT_STRCASENE(str1, str2):检讨 str1 和 str2 是不同的字符串,忽略大小写。用于浮点数比较的断言:
EXPECT_FLOAT_EQ(val1, val2):检讨 val1 和 val2 具有相同的浮点值。EXPECT_DOUBLE_EQ(val1, val2):检讨 val1 和 val2 具有相同的双精度值。EXPECT_NEAR(val1, val2, abs_error):检讨 val1 和 val2 之间的差值在 abs_error 范围内。用于布尔值的断言:
EXPECT_TRUE(condition):检讨 condition 为真。EXPECT_FALSE(condition):检讨 condition 为假。利用示例项目构造:
gtest_demo/├── CMakeLists.***├── include/│ └── math_functions.h├── src/│ └── math_functions.cpp└── tests/ └── test_math_functions.cpp
CMakeLists.***:
# 指定CMake的最低版本cmake_minimum_required(VERSION 3.10)# 定义项目名称project(gtest_demo)# 设置C++标准为C++11,并且为逼迫哀求set(CMAKE_CXX_STANDARD 11)set(CMAKE_CXX_STANDARD_REQUIRED True)# 添加当前项目的include目录,以便编译器能找到头文件include_directories(${PROJECT_SOURCE_DIR}/include)# 添加源文件,天生一个名为math_functions的静态库add_library(math_functions src/math_functions.cpp)# 查找Google Test库,确保系统已安装GTestfind_package(GTest REQUIRED)# 添加GTest的include目录include_directories(${GTEST_INCLUDE_DIRS})# 添加测试源文件,天生一个名为runTests的可实行文件add_executable(runTests tests/test_math_functions.cpp)# 链接math_functions, gtest库和pthread库到可实行文件runTests# gtest框架在实现上利用了多线程(pthread)来管理测试并发实行target_link_libraries(runTests ${GTEST_LIBRARIES} pthread math_functions)# 启用测试功能enable_testing()# 添加一个名为runTests的测试add_test(NAME runTests COMMAND runTests)
include/math_functions.h
#ifndef MATH_FUNCTIONS_H // 头文件保护#define MATH_FUNCTIONS_Hint add(int a, int b);int subtract(int a, int b);float add(float a, float b);double add(double a, double b);#endif
src/math_functions.cpp :
#include "math_functions.h"int add(int a, int b) { return a + b + 1; // 故意缺点}int subtract(int a, int b) { return a - b;}float add(float a, float b) { return a + b;}double add(double a, double b) { return a + b;}
tests/test_math_functions.cpp:
#include <gtest/gtest.h>#include "math_functions.h"// 测试add函数(整数)TEST(MathFunctionsTest, AddInt) { EXPECT_EQ(add(1, 1), 2); EXPECT_EQ(add(-1, -1), -2); EXPECT_EQ(add(0, 0),2); }// 测试subtract函数TEST(MathFunctionsTest, Subtract) { EXPECT_EQ(subtract(2, 1), 1); EXPECT_EQ(subtract(-1, -1), 0); EXPECT_EQ(subtract(0, 0), 0); }// 测试add函数(浮点数)TEST(MathFunctionsTest, AddFloat) { EXPECT_FLOAT_EQ(add(0.1f, 0.2f), 0.3f); EXPECT_NEAR(add(0.1f, 0.2f), 0.3f, 1e-6);}TEST(MathFunctionsTest, AddDouble) { EXPECT_DOUBLE_EQ(add(0.1, 0.2), 0.3); EXPECT_NEAR(add(0.1, 0.2), 0.3, 1e-6);}int main(int argc, char argv) { ::testing::InitGoogleTest(&argc, argv);// 初始化 Google Test return RUN_ALL_TESTS(); // 运行所有测试用例}
编译和运行测试
mkdir build cd build cmake.. make ./runTest
[==========] Running 4 tests from 1 test case.[----------] Global test environment set-up.[----------] 4 tests from MathFunctionsTest[ RUN ] MathFunctionsTest.AddInt/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:6: Failure Expected: add(1, 1) Which is: 3To be equal to: 2/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:7: Failure Expected: add(-1, -1) Which is: -1To be equal to: -2/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:8: Failure Expected: add(0, 0) Which is: 1To be equal to: 0[ FAILED ] MathFunctionsTest.AddInt (0 ms)[ RUN ] MathFunctionsTest.Subtract[ OK ] MathFunctionsTest.Subtract (0 ms)[ RUN ] MathFunctionsTest.AddFloat[ OK ] MathFunctionsTest.AddFloat (0 ms)[ RUN ] MathFunctionsTest.AddDouble[ OK ] MathFunctionsTest.AddDouble (0 ms)[----------] 4 tests from MathFunctionsTest (0 ms total)[----------] Global test environment tear-down[==========] 4 tests from 1 test case ran. (0 ms total)[ PASSED ] 3 tests.[ FAILED ] 1 test, listed below:[ FAILED ] MathFunctionsTest.AddInt 1 FAILED TEST
3个测试通过,1个不通过,add函数有误.
更多用法测试夹具测试夹具(Test Fixture)用于供应一个环境,许可开拓者在多个测试用例之间共享设置和清理的代码,确保每个测试用例都在相同或可控的初始状态下运行。
在gtest中,测试夹具常日是通过派生自::testing::Test类的子类来实现的,并通过TEST_F()宏定义测试用例。
示例:
#include <gtest/gtest.h>#include <vector>// 假设有一个大略的类 MyClassclass MyClass {public: MyClass(int data) : basevalue(data) {} void add(int data) { basevalue += data; } int getdata() const { return basevalue; }private: int basevalue;};// 测试夹具类class MyTest : public ::testing::Test {protected: MyClass my; std::vector<int> sharedVector; // 在每个测试用例实行前设置环境 void SetUp() override { my = new MyClass(100); sharedVector = {1, 2, 3, 4, 5}; } // 在每个测试用例实行后清理环境 void TearDown() override { delete my; }};// 利用 TEST_F() 宏编写测试用例TEST_F(MyTest, test1) { my->add(10); EXPECT_EQ(my->getdata(), 110); sharedVector.push_back(6); EXPECT_EQ(sharedVector.size(), 6); EXPECT_EQ(sharedVector.back(), 6);}TEST_F(MyTest, test2) { my->add(100); EXPECT_EQ(my->getdata(), 200); sharedVector.pop_back(); EXPECT_EQ(sharedVector.size(), 4); EXPECT_EQ(sharedVector.back(), 4);}TEST_F(MyTest, test3) { my->add(-50); EXPECT_EQ(my->getdata(), 50); sharedVector[0] = 10; EXPECT_EQ(sharedVector[0], 10); EXPECT_EQ(sharedVector.size(), 5);}TEST_F(MyTest, test4) { my->add(0); EXPECT_EQ(my->getdata(), 100); sharedVector.clear(); EXPECT_TRUE(sharedVector.empty());}
在这个示例中,测试夹具类 MyTest 通过继续 ::testing::Test 类,实现了 SetUp() 和 TearDown() 方法。在 SetUp() 方法中,初始化了一个 MyClass 工具和一个 std::vector<int>。在 TearDown() 方法中,清理了 MyClass 工具。
每个测试用例 (test1、test2、test3 和 test4) 都利用了相同的测试夹具 MyTest,共享了初始化和清理代码。在每个测试用例中,MyClass 工具和 sharedVector 都被重新初始化,以确保测试用例之间相互独立。
本文系作者个人观点,不代表本站立场,转载请注明出处!