【C++】Google Test(gtest)单元测试

二进制人工智能 2024-08-04 13:35:01 阅读 91

文章目录

Google Test(gtest)单元测试使用示例更多用法测试夹具

Google Test(gtest)单元测试

单元测试是一种软件测试方法,它旨在将应用程序的各个部分(通常是方法或函数)分离出来并独立测试,以确保每个部分都能够按预期工作。

gtest是Google公司发布的一款开源的C/C++单元测试框架。gtest的<code>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):检查 str1str2 是相同的字符串。EXPECT_STRNE(str1, str2):检查 str1str2 是不同的字符串。EXPECT_STRCASEEQ(str1, str2):检查 str1str2 是相同的字符串,忽略大小写。EXPECT_STRCASENE(str1, str2):检查 str1str2 是不同的字符串,忽略大小写。

用于浮点数比较的断言:

EXPECT_FLOAT_EQ(val1, val2):检查 val1val2 具有相同的浮点值。EXPECT_DOUBLE_EQ(val1, val2):检查 val1val2 具有相同的双精度值。EXPECT_NEAR(val1, val2, abs_error):检查 val1val2 之间的差值在 abs_error 范围内。

用于布尔值的断言:

EXPECT_TRUE(condition):检查 condition 为真。EXPECT_FALSE(condition):检查 condition 为假。

使用示例

项目结构:

gtest_demo/

├── CMakeLists.txt

├── include/

│ └── math_functions.h

├── src/

│ └── math_functions.cpp

└── tests/

└── test_math_functions.cpp

CMakeLists.txt

# 指定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库,确保系统已安装GTest

find_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_H

int 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: 3

To be equal to: 2

/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:7: Failure

Expected: add(-1, -1)

Which is: -1

To be equal to: -2

/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:8: Failure

Expected: add(0, 0)

Which is: 1

To 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>

// 假设有一个简单的类 MyClass

class 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 对象。

每个测试用例 (test1test2test3test4) 都使用了相同的测试夹具 MyTest,共享了初始化和清理代码。在每个测试用例中,MyClass 对象和 sharedVector 都被重新初始化,以确保测试用例之间相互独立。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。