卡冈图亚

Breski

@卡冈图亚

  • 黄思博 Post #1

    众所周知,这一代大学生不仅自私、喜好诡计和诈骗欺凌、热衷于窝里斗,和稀​​泥、普遍淡漠冷酷忌妒。在很多人眼里,这一代大学生就是毫无道德廉耻的"精英"做题家。这一代大学生真的像这样坏透底了吗?我想听听你们这些"精英"大学生的看法。

  • sumire アイラちゃん Post #155

    学习了一下 GoogleTest,把自己虚拟机的工具链更新到 clang20(废了好大劲) 😵‍💫
    但是自主学习的时光是快乐的,一边学一边摸鱼,一会儿再刷刷 B 站,堕落的人生呀 😋

    Notes

    GoogleTest

    这里学习一下相关 googleTest 的功能。
    全文来源于:GoogleTest。笔者只进行翻译和自我理解。

    安装与启动

    首先我们创建一个属于自己的工作区(文件夹)。创建工作区的部分可以参考 配置 ,不同系统上略有不同但 unix 类型系统都差不多。windows 是异端!

    接下来撰写我们的 cmake 文件。首先来安装相关的库。

    # 最小版本要求
    cmake_minimum_required(VERSION 3.22)
    # 自定义 debug 模式参数。
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall")
    # 设定编译器和 C++ 标准
    set(CMAKE_C_COMPILER "/usr/bin/clang")
    set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
    set(CMAKE_VERBOSE_MAKEFILE ON)
    set(CMAKE_CXX_STANDARD 20)
    # 项目名。
    project(main)
    
    include(FetchContent)
    FetchContent_Declare(
      googletest
      URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
    )
    FetchContent_MakeAvailable(googletest)
    set(ENV{HTTP_PROXY} "http://localhost:1080")    # 没办法,gfw
    

    然后我们编写一个简单的测试程序

    #include <gtest/gtest.h>
    // Demonstrate some basic assertions.
    TEST(HelloTest, BasicAssertions) {
      // Expect two strings not to be equal.
      EXPECT_STRNE("hello", "world");
      // Expect equality.
      EXPECT_EQ(7 * 6, 42);
    }
    

    最后增加以下部分开启 googletest。

    enable_testing()        # 开启测试
    add_executable(main main.cpp)   # 增加可执行文件和其源文件。
    target_link_libraries(
        main
        GTest::gtest_main
    )       # 链接 gtest 动态库。
    include(GoogleTest) # 包含头文件。
    gtest_discover_tests(main)  # 自动寻找测试项目。
    

    从源码安装

    git clone https://github.com/google/googletest.git
    cd googletest/
    mkdir build
    cd build
    cmake ..
    make
    sudo make install
    

    cmake 脚本变成:

    cmake_minimum_required(VERSION 3.22)
    
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall")
    
    set(CMAKE_C_COMPILER "/usr/bin/clang")
    set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
    set(CMAKE_VERBOSE_MAKEFILE ON)
    set(CMAKE_CXX_STANDARD 20)
    
    project(main)
    
    enable_testing()
    find_package(GTest REQUIRED)
    
    add_executable(main main.cpp)
    target_link_libraries(
        main
        GTest::gtest_main
    )
    include(GoogleTest)
    gtest_discover_tests(main)
    

    测试的一些基本原则

    • 独立/可重复。
    • 具有良好的结构,可以反应测试代码的结构。
    • 可重用且可移植。
    • 提示足够多的相关问题的信息,当测试失败的时候,可以提示该测试失败的信息,并且继续执行其他部分。
    • 专注于测试的内容而非其他的一些杂项。
    • 足够快。

    基本概念

    一般而言,googleTest 将从断言开始书写。断言将会判断你的一个语句是否是真。

    • 断言的结果一般有三种:
      • (非致命性)失败,(致命性)失败与成功。
      • 当一个致命性失败出现时,当前函数将会中断。否则程序将会继续正常运行。

    测试通过断言来验证代码的行为。当测试故障或出现一个(致命性)错误断言时,测试程序中止,否则它将会成功。

    一个测试组 (test suites) 将会包括一个或者多个测试,你可以将测试集合成多个测试组来反应测试代码的结构。多个测试在同一组中采用共享对象和子进程时,可以放入一个 test fixture 类中。

    一个测试程序可以有多个测试组 (test suites)。

    断言

    主要分为两种:ASSERT_*(抛出致命性错误),EXPECT_*(抛出非致命性错误)。前者需要注意可能的内存泄漏问题,因为函数将会提前终止。

    我们可以通过 << 来输出错误时我们的报错信息。例如:
    EXPECT_EQ(7 * 5, 42) << "The calculation result should be 42!\n";是非致命性报错,因此会继续往下执行到达程序结束。

    img

    任何的可以通过 ostream 输出的方式都可以通过断言输出。

    简单测试

    创建一个测试:

    1. 使用 TEST() 宏来定义和命名一个测试函数。这是常用的 C++ 的函数,并且没有返回值。
    2. 在这个函数中,任何合法的 C++ 语句都可以被 include,并且采用断言检查值。
    3. 测试结果通过断言进行决定。如果任何断言致命性失败,或者测试程序崩溃,整个测试就将会失败。否则,它将会执行结束。
    TEST(TestSuiteName, TestName) {
        // Test Body
    }
    

    我们可以写出一个简单的阶乘测试

    #include <gtest/gtest.h>
    
    template<class T>
    T factorial(T n) {
        if(n == 1 || n == 0) return 1;
        else return factorial(n-1) * n;
    }
    
    TEST(MyTest, TestFactorialCase) {
        // Case statement.
        EXPECT_EQ(factorial(0), 1);
        EXPECT_EQ(factorial(1), 1);
    }
    TEST(MyTest, TestFactorialNormal) {
        // Some cases.
        EXPECT_EQ(factorial(1), 1);
        EXPECT_EQ(factorial(2), 2);
        EXPECT_EQ(factorial(3), 6);
        EXPECT_EQ(factorial(8), 40320);
    }
    

    img

    Test Fixtures:多测试中采用相同数据配置

    当你发现你在相同数据上写两个/多个测试,并且需要用到相同的数据配置时,可以使用 test fixture,这样在不同测试中可以使用相同的对象配置。
    创建一个 Fixture:

    1. testing::Test 中继承一个新的类。从 protected 部分开始编写。
    2. 在类中,可以声明任意的对象。
    3. 如果必要,书写一个默认的构造函数 SetUp() 来对每一个测试进行准备。注意拼写!
    4. 如果必要,书写一个析构函数来销毁所有的在构造函数中分配的资源。
    5. 如有必要,构建子程序来告诉你的测试进行共享。

    TestSuite 采用如下的格式

    TEST_F(TestFixtureClassName, TestName) {
        // 测试函数体
    }
    

    这样我们可以编写示例函数:

    #include <gtest/gtest.h>
    #include <queue>
    
    class QueueTest: public testing::Test {
        protected:
            std::queue<int> q0, q1, q2;
            QueueTest() {
                q1.push(1);
                q2.push(2);
                q2.push(3);
            }
    };
    TEST_F(QueueTest, IsEmptyInitially) {
        EXPECT_EQ(q0.size(), 0);
    }
    TEST_F(QueueTest, DequeueWorks) {
        EXPECT_EQ(q0.empty(), true);
    
        int n = q1.front();
        EXPECT_EQ(n, 1);
        q1.pop();
        EXPECT_EQ(q1.size(), 0);
    
        n = q2.front();
        EXPECT_EQ(n, 2);
        q2.pop();
        EXPECT_EQ(q2.size(), 1);
    }
    

    添加 main 函数

    我们可以将 google test 集成到 main 函数中。这样我们可以实现执行其他部分的功能。main 函数的一个实例如下:

    int main() {
        testing::InitGoogleTest();
        int status = RUN_ALL_TESTS();
        return status;
    }
    

    status = 0 代表执行成功,否则其他情况将返回 1.

    更进一步

    接下来将进入更多的技巧,例如复杂的失败信息,传递致命性失败信息,重用和提高测试集合速度,以及采用不同的 flags。

    更多的断言

    • 显式的成功和失败。
      • SUCCEED(), FAIL()(致命性),ADD_FAILURE(file, line)(非致命性)。ADD_FAILURE_AT() 在指定文件和行后增加非致命性信息。
    • 异常断言
      • EXPECT/ASSERT_THROW(statement, exception_type)验证抛出特定类型的错误。

    复杂分枝

    采用一以下函数来提供比 EXPECT_TRUE(statement) 更好的消息。

    testing::AssertionResult IsEven(int n) {
      if ((n % 2) == 0)
        return testing::AssertionSuccess();
      else
        return testing::AssertionFailure() << n << " is odd";
    }
    // bool IsEven(int n) {
    //   return (n % 2) == 0;
    // }
    

    浮点数比较

    采用以下方式来进行简单但是比较全面的比较。

    using ::testing::FloatLE;
    using ::testing::DoubleLE;
    // ...
    EXPECT_PRED_FORMAT2(FloatLE, val1, val2);
    EXPECT_PRED_FORMAT2(DoubleLE, val1, val2);
    
  • 夜阑观星海 夜阑观星海 Post #2

    其实也没有多不一样,应该说只是高估了社交和信息渠道的来源,上着上着发现就进入了毫无社交的循环自闭状态……一眼看得到头了

  • ❤️ Liked post in 猪圈土源分圈:pig2:
    谈笑风生
    青年杰出贡献上交大門人 紫金港第一皮革<・)))><< Post #1

    欢迎各位皮革兔前来哼哼哼哼哼!!

  • LittleWangInShanghai 小王在上海 Post #43

    某个专业课老师认为大学最后两年至少每个月要精读一本本专业专著才能弥补被荒废的时光。

  • IO IO Post #2

    真的是 高高在上呢

  • ❤️ Liked post in 最人物:六小龄童
    谈笑风生
    一只玉米人 玉米🌽 Post #1
  • uika_winwing uika_winwing Post #9

    读研是这样的吗,害怕了

  • anonymous_coward_old Anonymous Coward Old Post #7

    我建了一个 本站的 GitHub 组织 xjtumen,可以加入这个组织。

    这个仓库专门收集这类脚本:

    https://github.com/xjtumen/automation

    欢迎提交 Pull Request (PR) 上传你的脚本。