# Google Test Tutorial
## **為什麼用 Google Test (gtest)**
Google Test (gtest) 是一個由 Google 開發的 C++ 單元測試框架,用於檢查程式的功能是否正常。它可以幫助我們快速檢查專案或程式內的C/C++函式是否正確執行。
## gtest程式介紹
以下為一個最基本的範例程式檔設計
:::spoiler example.cpp
```Cpp=
//example.cpp
#include <gtest/gtest.h>
// 測試的函式(可以從其他檔案中引入)
int add(int a, int b){
return a+b;
}
//測試案例一
TEST(testCase, test1){
EXPECT_EQ(myadd(1, 2), 3);
}
//測試案例二
TEST(testCase, test2){
EXPECT_EQ(myadd(1, -1), 0);
}
// 主函式:執行所有測試案例
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
:::
### 解說
1. 被檢測的函式
- 可以直接在gtest檔案裡宣告,也可以引入其他檔案的函式
- 引入其他檔案的函式,舉例:
#### example.h
```h=
#pragma once
int add(int a, int b);
```
#### example.c
```C=
#include "example.h"
int add(int a, int b) {
return a + b;
}
```
#### gtest.cpp
```Cpp=
#include <gtest/gtest.h>
extern "C" {
#include "example.h" // 引入要測試的函式
}
TEST(AdditionTest, PositiveNumbers) {
EXPECT_EQ(add(2, 3), 5);
}
//接主程式
```
2. 測試函式
```Cpp=
Test(類別,測試名){
//你的程式碼
}
```
- 類別和測試名的設置在測試時會顯示出來
- 如:
- 加法函數測試一,正數加減
- 加法函數測試二,負數加減
- 乘法函數測試一,100內相乘
- 前為類別,後為測試名
- 程式碼區域則需使用斷言函式,常見的斷言函式有:
### **值比較**
| 函式 | 描述 | 範例 |
|-----------------------|-------------------------------------------|-----------------------------------|
| `EXPECT_EQ(val1, val2)` | 檢查兩個值是否相等 | `EXPECT_EQ(3, add(1, 2));` |
| `EXPECT_NE(val1, val2)` | 檢查兩個值是否不相等 | `EXPECT_NE(3, subtract(1, 2));` |
| `EXPECT_LT(val1, val2)` | 檢查 `val1` 是否小於 `val2` | `EXPECT_LT(2, 5);` |
| `EXPECT_LE(val1, val2)` | 檢查 `val1` 是否小於等於 `val2` | `EXPECT_LE(5, 5);` |
| `EXPECT_GT(val1, val2)` | 檢查 `val1` 是否大於 `val2` | `EXPECT_GT(5, 2);` |
| `EXPECT_GE(val1, val2)` | 檢查 `val1` 是否大於等於 `val2` | `EXPECT_GE(5, 5);` |
### **布林值檢查**
| 函式 | 描述 | 範例 |
|--------------------------|--------------------------------|-------------------------------|
| `EXPECT_TRUE(condition)` | 檢查條件是否為 `true` | `EXPECT_TRUE(isPositive(5));` |
| `EXPECT_FALSE(condition)`| 檢查條件是否為 `false` | `EXPECT_FALSE(isNegative(5));`|
---
### **浮點數檢查**
用於比較浮點數(解決精度問題)。
| 函式 | 描述 | 範例 |
|--------------------------------|-------------------------------------------|------------------------------------------|
| `EXPECT_FLOAT_EQ(val1, val2)` | 檢查兩個浮點數是否相等(以小數精度比較) | `EXPECT_FLOAT_EQ(0.1 + 0.2, 0.3);` |
| `EXPECT_NEAR(val1, val2, abs_error)` | 檢查兩個值是否在允許誤差範圍內 | `EXPECT_NEAR(3.14, computePi(), 0.01);` |
### **字串比較**
| 函式 | 描述 | 範例 |
|-----------------------------------|------------------------------------------|---------------------------------------------|
| `EXPECT_STREQ(str1, str2)` | 檢查兩個 C 字符串是否相等 | `EXPECT_STREQ("hello", getGreeting());` |
| `EXPECT_STRNE(str1, str2)` | 檢查兩個 C 字符串是否不相等 | `EXPECT_STRNE("hello", "world");` |
| `EXPECT_STRCASEEQ(str1, str2)` | 檢查兩個 C 字符串是否相等(忽略大小寫) | `EXPECT_STRCASEEQ("hello", "HELLO");` |
| `EXPECT_STRCASENE(str1, str2)` | 檢查兩個 C 字符串是否不相等(忽略大小寫)| `EXPECT_STRCASENE("hello", "WORLD");` |
---
### 即時終止測試的斷言
**`ASSERT_*` 系列** 與 `EXPECT_*` 類似,但當斷言失敗時會立即終止該測試案例,而不執行後續測試。
| 函式 | 描述 | 範例 |
|-----------------------|-------------------------------------------|-----------------------------------|
| `ASSERT_EQ(val1, val2)` | 檢查兩個值是否相等 | `ASSERT_EQ(3, add(1, 2));` |
| `ASSERT_NE(val1, val2)` | 檢查兩個值是否不相等 | `ASSERT_NE(3, subtract(1, 2));` |
| `ASSERT_TRUE(condition)`| 檢查條件是否為 `true` | `ASSERT_TRUE(isValid(value));` |
| `ASSERT_FALSE(condition)`| 檢查條件是否為 `false` | `ASSERT_FALSE(isNegative(5));` |
---
3. 主程式
一般情況下利用其配套好的程式就好,會執行所有測試案例
```Cpp=
// 主函式:執行所有測試案例
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
## 設計自己的gtest
1. 確認是否引用外部函式
2. 新增想要測試的斷言函式
3. 主程式帶入,執行所有測試案例
## 利用Cmake執行gtest
### cmake安裝
確認自己是否安裝cmake
```bash
sudo apt-get install cmake
cmake --version
```
### 建立專案資料夾或進入被測試檔案的專案資料夾
```bash
mkdir my_project && cd my_project
```
### 當前資料夾路徑預覽
我們的資料夾等等應該長這樣
```
my_project
├── CMakeLists.txt
├── example.c
├── example.h
└── my_gtest.cpp
```
### 在被測試檔案同層資料夾創立CMakeLists.txt
這邊是固定的,不須修改,此為從github中下載gtest
```txt
cmake_minimum_required(VERSION 3.14)
project(my_project)
# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
```
### 建立/引用相關檔案
以下為範例檔,需換成自己的檔案
:::spoiler example.c
```C=
#include "example.h"
int myadd(int a, int b) {
return a + b;
}
```
:::
:::spoiler example.h
```h=
#pragma once
int myadd(int a, int b);
```
:::
:::spoiler my_gtest.cpp
```Cpp=
#include <gtest/gtest.h>
extern "C" {
#include "example.h" // 引入要測試的函式
}
TEST(testCase, test1){
EXPECT_EQ(myadd(1, 2), 3);
}
//測試案例二
TEST(testCase, test2){
EXPECT_EQ(myadd(1, -1), 0);
}
// 主函式:執行所有測試案例
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
:::
### Cmake配置Google Test 測試執行環境,需加在CMakeLists.txt末尾
```txt
enable_testing() //啟用 CMake 的測試功能
add_library(myadd example.c) //將被測試檔編譯成函式庫,供多個檔案使用,這邊自訂為myadd
add_executable( //將測試程式編譯為一個可執行檔案
my_gtest //測試檔的執行檔(換成自己的)
my_gtest.cpp //測試檔原檔(換成自己的)
)
target_link_libraries( //將 Google Test 等函式庫鏈接到可執行檔 my_gtest
my_gtest //可執行檔(換成自己的)
myadd //自訂函式庫(換成自己的)
GTest::gtest_main
)
include(GoogleTest) //引入 Google Test 的 CMake 模組
gtest_discover_tests(my_gtest) //自動找尋my_gtest(換成自己的)中的gtest測試案例,註冊到ctest框架中
```
### 下指令執行
#### 在被測試函式檔同層資料夾下指令
```bash=
cmake -S . -B build //配置專案,會自行創立build資料夾,不須自行新增
cmake --build build //編譯專案
cd build && ctest //執行測試
```
### 此時資料夾預覽
```
my_project
├── build
├── CMakeLists.txt
├── example.c
├── example.h
└── my_gtest.cc
```
執行完上述指令就成功完成了自己的gtest啦!!
