GoogleTest学习实践

第1步:环境安装与配置

对于Linux系统

# 安装编译依赖
sudo apt-get install build-essential cmake libgtest-dev

# 编译安装
cd /usr/src/gtest
sudo cmake CMakeLists.txt
sudo make
sudo cp *.a /usr/lib

CMake集成示例

cmake_minimum_required(VERSION 3.14)
project(MyTests)

find_package(GTest REQUIRED)
add_executable(runTests test.cpp)
target_link_libraries(runTests GTest::GTest GTest::Main)

第2步:编写第一个测试

创建test.cpp:

#include 

TEST(MyFirstTest, BasicAssertion) {
    EXPECT_EQ(2+2, 4);   // 期望相等
    ASSERT_TRUE(1 < 2);  // 断言为真
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

编译运行:

mkdir build && cd build
cmake .. && make
./runTests

第3步:核心断言类型

基本断言

ASSERT_TRUE(condition);  // 致命断言
EXPECT_FALSE(condition); // 非致命断言

值比较

EXPECT_EQ(val1, val2);   // ==
ASSERT_NE(val1, val2);   // !=
EXPECT_LT(val1, val2);   // <
ASSERT_LE(val1, val2);   // <=

字符串比较

ASSERT_STREQ(str1, str2);    // C字符串相等
EXPECT_STRCASEEQ(str1, str2); // 忽略大小写

第4步:测试夹具(Test Fixtures)

创建可复用的测试环境:

class VectorTest : public ::testing::Test {
protected:
    void SetUp() override {
        vec.push_back(1);
        vec.push_back(2);
    }

    void TearDown() override {
        vec.clear();
    }

    std::vector<int> vec;
};

TEST_F(VectorTest, SizeTest) {
    ASSERT_EQ(vec.size(), 2);
}

TEST_F(VectorTest, CapacityTest) {
    EXPECT_GE(vec.capacity(), 2);
}

第5步:参数化测试

使用不同参数运行相同测试逻辑:

class NumberTest : public ::testing::TestWithParam<int> {};

INSTANTIATE_TEST_SUITE_P(EvenNumbers, NumberTest,
                         ::testing::Values(2, 4, 6, 8));

TEST_P(NumberTest, IsEven) {
    int num = GetParam();
    ASSERT_EQ(num % 2, 0);
}

第6步:高级断言

异常断言

TEST(ExceptionTest, ThrowTest) {
    EXPECT_THROW({
        throw std::runtime_error("error");
    }, std::runtime_error);
}

浮点数比较

ASSERT_DOUBLE_EQ(1.0000001, 1.0);       // 4ULP精度
EXPECT_NEAR(1.0, 1.0001, 0.001);       // 绝对误差

死亡测试(验证程序崩溃)

TEST(DeathTest, InvalidAccess) {
    int* ptr = nullptr;
    EXPECT_DEATH(*ptr = 1, ".*");
}

第7步:Mocking(需要GoogleMock)

创建模拟对象:

#include 

class Database {
public:
    virtual ~Database() = default;
    virtual int query(const std::string&) = 0;
};

class MockDB : public Database {
public:
    MOCK_METHOD(int, query, (const std::string&), (override));
};

TEST(DatabaseTest, QueryTest) {
    MockDB db;
    EXPECT_CALL(db, query("test"))
        .WillOnce(::testing::Return(42));
    
    ASSERT_EQ(db.query("test"), 42);
}

第8步:最佳实践

  1. 测试命名规范:TestSuiteName.TestCaseName

  2. 每个测试保持独立,不依赖执行顺序

  3. 使用夹具减少重复代码

  4. 断言失败信息增强:

ASSERT_EQ(a, b) << "a=" << a << ", b=" << b;
  1. 控制测试执行:
./runTests --gtest_filter=TestSuite.*       # 运行指定测试
./runTests --gtest_repeat=1000 --gtest_break_on_failure  # 重复测试

第9步:高级功能

类型参数化测试:

template <typename T>
class TypedTest : public ::testing::Test {};
TYPED_TEST_SUITE_P(TypedTest);

TYPED_TEST_P(TypedTest, Size) {
    TypeParam vec;
    EXPECT_EQ(vec.size(), 0);
}

REGISTER_TYPED_TEST_SUITE_P(TypedTest, Size);
using MyTypes = ::testing::Types<std::vector<int>, std::list<float>>;
INSTANTIATE_TYPED_TEST_SUITE_P(My, TypedTest, MyTypes);

时间测量

TEST(TimingTest, FastOperation) {
    EXPECT_EXIT({
        // 被测代码
    }, ::testing::ExitedWithCode(0), "") 
    << "Operation took too long";
}

第10步:集成到CI/CD

示例GitLab CI配置:

test_job:
  stage: test
  script:
    - mkdir build
    - cd build
    - cmake ..
    - make
    - ./runTests --gtest_output="xml:test_results.xml"
  artifacts:
    reports:
      junit: build/test_results.xml

学习资源:

官方文档:https://google.github.io/googletest/

GitHub仓库:https://github.com/google/googletest

高级技巧:https://chromium.googlesource.com/external/github.com/google/googletest/+/HEAD/docs/advanced.md

你可能感兴趣的:(c/c++,c++,单元测试,功能测试)