gtest

在vs2022中使用cmake添加vcpkg管理的gtest库

1.在CMakePresets.json中添加配置

1
2
3
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "C:/D/test/CC++/cc++lib/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake"
}

项目结构

1

根目录文件

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.15)

# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()

project ("CMakeProject2")

# Include sub-projects.
add_subdirectory ("CMakeProject2")
add_subdirectory ("CMakeProject3")
add_subdirectory ("unit_tests")
# 启用测试
enable_testing()

CMakePresets.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
{
"version": 3,
"configurePresets": [
{
"name": "windows-base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_TOOLCHAIN_FILE": "C:/D/test/CC++/cc++lib/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "x64-debug",
"displayName": "x64 Debug",
"inherits": "windows-base",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x64-release",
"displayName": "x64 Release",
"inherits": "x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "x86-debug",
"displayName": "x86 Debug",
"inherits": "windows-base",
"architecture": {
"value": "x86",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x86-release",
"displayName": "x86 Release",
"inherits": "x86-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
},
{
"name": "macos-debug",
"displayName": "macOS Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
}
]

}

CMakeProject2

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 定义一个静态库,包含所有业务逻辑的实现
# 这样 MyPrint 和 MyClass 的二进制代码就会被打包进这个库
add_library(MyClassLib STATIC
"MyClass.cpp"
"MyClass.h"
)

# 2. 设置头文件路径 (PUBLIC 表示链接这个库的人也能看到这些头文件)
target_include_directories(MyClassLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

# 3. 让主程序只包含 main 函数所在的 cpp,并链接库
add_executable(CMakeProject2 "CMakeProject2.cpp")
target_link_libraries(CMakeProject2 PRIVATE MyClassLib)

# 设置 C++ 标准
set_property(TARGET MyClassLib PROPERTY CXX_STANDARD 20)
set_property(TARGET CMakeProject2 PROPERTY CXX_STANDARD 20)

CMakeProject2.cpp

1
2
3
4
5
6
7
8
9
10
#include "myclass.h"


int main() {
MyPrint(L"Hello ");
MyClass myClass;
myClass.CPrint(L"World!\n");
myClass.CPrint();
}

MyClass.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//写出头文件预定义g++风格
#ifndef MYCLASS_H
#define MYCLASS_H
#include <Windows.h>

class MyClass {
public:
MyClass();
~MyClass();
void CPrint(const wchar_t* str);
int CPrint();
};

void MyPrint(const wchar_t* str);
#endif // MYCLASS_H

MyClass.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "myclass.h"

MyClass::MyClass() {
MyPrint(L"MyClass constructor called.\n");
}

MyClass::~MyClass() {
CPrint(L"MyClass destructor called.\n");
}
void MyClass::CPrint(const wchar_t* str) {
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str), nullptr, nullptr);
}
int MyClass::CPrint() {
MyPrint(L"CPrint method called.\n");
return 0; // 返回一个示例值
}


void MyPrint(const wchar_t* str) {
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wcslen(str), nullptr, nullptr);
}

CMakeProject3

CMakeLists.txt

1
2
3
4
5
add_executable(CMakeProject3 "CMakeProject3.cpp")

if (CMAKE_VERSION VERSION_GREATER 3.15)
set_property(TARGET CMakeProject3 PROPERTY CXX_STANDARD 20)
endif()

CMakeProject3.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdint>
#include <string>
#include <Windows.h>

using namespace std;

int main() {
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"Hello ", 6, nullptr, nullptr);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"World!\n", 7, nullptr, nullptr);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"Enter your name: ", 17, nullptr, nullptr);
wstring name(1024, 0);
int32_t numberOfCharsRead = 0;
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), (LPVOID)name.c_str(), 1024, (LPDWORD)&numberOfCharsRead, nullptr);
name.resize(numberOfCharsRead - 2);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"Good day, ", 10, nullptr, nullptr);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), name.c_str(), static_cast<int32_t>(name.length()), nullptr, nullptr);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"!\n", 2, nullptr, nullptr);
}

// This code produces the following output:
//
// Hello World!
// Enter your name: James
// Good day, James!

unit_tests

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 寻找 GTest (由 vcpkg 提供)
find_package(GTest CONFIG REQUIRED)

# 你的测试源码
add_executable(unit_tests "test_example.cpp")

target_compile_features(unit_tests PRIVATE cxx_std_20)

# gtest_main 会自动提供 main(),你不需要在 cpp 里写 main
# 关键:链接业务类库和 GTest 库
target_link_libraries(unit_tests PRIVATE
MyClassLib
GTest::gtest_main
GTest::gtest
)

# 自动发现并注册测试
include(GoogleTest)
gtest_discover_tests(unit_tests)

test_example.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <gtest/gtest.h>
#include <Windows.h>
#include "MyClass.h"

// 1. 测试全局函数 MyPrint 是否能正常调用
TEST(GlobalFunctionTest, MyPrintCall) {
// 验证调用 MyPrint 不会引发崩溃或异常
// 在单元测试中,由于可能没有控制台窗口,这主要验证逻辑可执行性
EXPECT_NO_THROW(MyPrint(L"Testing global MyPrint...\n"));
}

// 2. 测试 MyClass 的核心功能
class MyClassTest : public ::testing::Test {
protected:
// 每个测试用例开始前都会创建一个新的 MyClass 实例
MyClass* instance;

void SetUp() override {
instance = new MyClass();
}

void TearDown() override {
delete instance;
}
};

// 验证 CPrint() 无参方法的返回值
TEST_F(MyClassTest, CPrintReturnsCorrectValue) {
// 根据你的实现,CPrint() 应该返回 0
int result = instance->CPrint();
EXPECT_EQ(result, 0) << "CPrint() method should return 0.";
}

// 验证带参数的 CPrint(const wchar_t*) 是否能运行
TEST_F(MyClassTest, CPrintWithParamsCall) {
EXPECT_NO_THROW(instance->CPrint(L"Testing MyClass::CPrint with string...\n"));
}