# GoogleTest 教學
GoogleTest 是 Google 的 C++ 測試框架,可以對 C++ 程式進行單元測試,也就是對程式碼中的單個組件進行測試,例如 function , class,透過進行單元測試,開發者可以快速找到問題所在之處,節省時間成本。因為 C++ 可以兼容 C,因此 GoogleTest 也可用來做 C 的測試。
## 編寫 GoogleTest 測試程式
這邊寫了一個 gcd 函式進行教學示範
:::spoiler gcd.h
```c=
#pragma once
#include<stdio.h>
#include<stdint.h>
#include<math.h>
int32_t gcd(int32_t , int32_t);
```
:::
:::spoiler gcd.c
```c=
#include "gcd.h"
int32_t gcd(int32_t a, int32_t b){
if(a <= 0 || b <= 0)return -1;
while(b > 0){
int32_t tmp = b;
b = a % b;
a = tmp;
}
return a;
}
```
:::
### 建立測試程式
首先,在專案中創立一個 `hello_test.cc` C++ 檔案,當然你也可以取你喜歡的檔名。
要使用 GoogleTest,當然需要先引入函式庫
```cpp!
#include <gtest/gtest.h>
```
接下來要引入我們的程式,因為我們寫的是 C,因此需要加上 `extern "C"`
```cpp!
extern "C" {
#include "gcd.h"
}
```
### 建立 TEST 測試單元
在我們剛剛建立的程式中寫一個測試單元,我們使用TEST巨集建立測試函數,使用方法如下
```!
TEST(測試集, 測試名){
這裡可以包含任何 C++ 程式,並使用 GoogleTest 的斷言函式檢查數值,如果任何一個斷言巨集錯誤,那就代表這個測試失敗
}
```
GoogleTest的斷言巨集可以到[這裡](https://google.github.io/googletest/reference/assertions.html)找,主要分為兩種,`EXPECT` 和 `ASSERT`,`EXPECT`在錯誤時還會繼續執行後面的程式,而 `ASSERT` 發生錯誤時會直接中止該項測試函數。
這邊列出幾個常用的
- `EXPECT_EQ( val1, val2 )`、`ASSERT_EQ( val1, val2 )`
比較兩個值是否相等
- `EXPECT_NE( val1, val2 )`、`ASSERT_NE( val1, val2 )`
比較兩個值是否不同
- `EXPECT_STREQ( str1, str2 )`、`ASSERT_STREQ( str1, str2 )`
比較兩個字串是否相同
使用 gcd 來進行示範,我創建了一個 vaildinput 和一個 invalidinput 測試,都是 gcd 測試集
```cpp!
TEST(gcd, vaildinput){
EXPECT_EQ(gcd(16, 24), 8);
EXPECT_EQ(gcd(9, 3), 3);
}
TEST(gcd, invalidinput){
EXPECT_EQ(gcd(0, 0), -1);
EXPECT_EQ(gcd(0, -1), -1);
}
```
:::spoiler 完整程式碼
```cpp=
#include <gtest/gtest.h>
extern "C" {
#include "gcd.h"
}
TEST(gcd, vaildinput){
EXPECT_EQ(gcd(16, 24), 8);
EXPECT_EQ(gcd(9, 3), 3);
}
TEST(gcd, invalidinput){
EXPECT_EQ(gcd(0, 0), -1);
EXPECT_EQ(gcd(0, -1), -1);
}
```
:::
## 使用CMake
### 建立 CMakeLists.txt
GoogleTest 需要使用 CMake 導入與編譯執行,需要確保電腦中有安裝 [CMake](https://cmake.org)。
在專案中建立 `CMakeLists.txt`,這個檔案裡面會寫這個專案的依賴項目。
這兩行是每個 CMakeLists 都必須加的,注意 GoogleTest 要求 CMake 版本最低要3.14
```cmake=
cmake_minimum_required(VERSION 3.14)
project(my_project)
```
### 引入 GoogleTest
在裡面加入這幾行,讓 CMake 從 GitHub 下載 GoogleTest 的檔案
```cmake=
# 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
)
FetchContent_MakeAvailable(googletest)
```
這樣 CMake 就會將 GoogleTest 引入專案當中了。
### 建立執行檔
首先要啟用測試
```cmake!
enable_testing()
```
加入你的函式庫
```cmake!
add_library(gcd gcd.c)
```
最後加入執行檔,連結函式庫還有連結到 GoogleTest
```cmake!
add_executable(
hello_test
hello_test.cc
)
target_link_libraries(
hello_test
gcd gtest_main
)
include(GoogleTest)
gtest_discover_tests(hello_test)
```
:::spoiler 完整 CMakeLists.txt
```cmake=
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
)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(
hello_test
hello_test.cc
)
target_link_libraries(
hello_test
gcd gtest_main
)
include(GoogleTest)
gtest_discover_tests(hello_test)
```
:::
## 編譯並執行
建立一個 build 資料夾,存放編譯後的資料及執行檔
現在專案目錄應該如下
```
my_project
├── build
├── CMakeLists.txt
├── gcd.c
├── gcd.h
└── hello_test.cc
```
接著告訴 CMake 目標位置
```bash!
cmake -S . -B build
```
進行建置
```bash!
cmake --build build
```
恭喜你,現在已經編譯完了,你應該會在 build 資料夾看到執行檔了
進到 build 資料夾中,並執行 ctest 應該就會開始進行測試了
```bash!
cd build
ctest
```
如果成功的話,就可以看到像這樣的輸出
```
> ctest
Test project .../my_project/build
Start 1: gcd.vaildinput
1/2 Test #1: gcd.vaildinput ................... Passed 0.01 sec
Start 2: gcd.invalidinput
2/2 Test #2: gcd.invalidinput ................. Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
Total Test time (real) = 0.02 sec
```
## 資源
- GoogleTest
https://google.github.io/googletest/
- CMake Tutorial
https://cmake.org/cmake/help/latest/guide/tutorial/index.html