gtest之高级主题

这篇具有很好参考价值的文章主要介绍了gtest之高级主题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

跳过test

GTEST_SKIP()会跳过测试程序,这在运行阶段根据条件执行测试非常有用。GTEST_SKIP()可以用在单个测试,或者是继承自::testing::Environment or ::testing::Test的class fixture中的SetUp()中。可以用GTEST_SKIP()输出信息,以下为官网示例

TEST(SkipTest, DoesSkip) {
  GTEST_SKIP() << "Skipping single test";
  EXPECT_EQ(0, 1);  // Won't fail; it won't be executed
}

class SkipFixture : public ::testing::Test {
 protected:
  void SetUp() override {
    GTEST_SKIP() << "Skipping all tests for this fixture";
  }
};

TEST_F(SkipFixture, SkipsOneTest) {
  EXPECT_EQ(5, 7);  // Won't fail
}

输出:
gtest之高级主题

打印自己的信息

    • 可以通过自定义函数,使用断言的输出流运算符打印自己想要的内容;
  1. 使用GoogleTest定义的函数:::testing::PrintToString(x),返回std::string,将x中的内容以字符串形式输出
TEST_F(SkipFixture, SkipsOneTest) {
  vector<int> v {6,3,7,9,3};
  EXPECT_EQ(5, 7) << "hello" << testing::PrintToString(v);
}

输出:(内容用{}包括)
gtest之高级主题

在子程序中使用断言

在Assertions中添加traces

一个测试的子程序会在很多地方被使用,很难判断它具体在哪个地方失败了,额外增加log等帮助信息会让测试程序显得很乱,gtest提供了解决方案:SCOPED_TRACE(message) 宏或者 ::testing::ScopedTrace trace("file_path", line_number, message);
SCOPED_TRACE(message)会打印出当前文件名,行号和message信息;::testing::ScopedTrace接收额外的文件名和行号,这对写test helper非常有帮助。
这两个宏/对象的有效范围在当前作用域内。

void Sub1(int n) {
    EXPECT_EQ(n,1);
    EXPECT_EQ(n,2);
}

TEST(SPTtest, case001) {
    {
        SCOPED_TRACE("A");
        ::testing::ScopedTrace trace("file_path", 122, "hello");
        Sub1(1);
    }
    Sub1(9);
}

输出:
gtest之高级主题

传播致命失败

  • TODO

log中添加信息

可以通过Test类中的静态函数RecordProperty来增加额外信息,RecordProperty以key,value作为参数,其中key必须符合xml中的属性名且不能和GoogleTest 中已存在的关键字冲突。
示例代码:

class LogAddi : public ::testing::Test { };

TEST_F(LogAddi, MinAndMaxWidgets) {
  RecordProperty("MaximumWidgets", "It's very nice");
  RecordProperty("aa", "good good study");
  EXPECT_TRUE(false);
}

和没有使用RecordProperty对比输出:
gtest之高级主题
注意这个只在输出(命令行通过–gtest_output=xml:.xml_path指定输出文件)中有效。

在同一test suite中共享资源

  1. 将共享资源声明为test fixture的static成员变量,在类外初始化;
  2. 在test fixture类中定义static成员函数void SetUpTestSuite()void TearDownTestSuite()设置/释放共享的static变量(最好声明为public,可以在TEST_P中使用)。
    GoogleTest 会在第一个测试程序运行前,甚至是实例化一个test fixture对象前运行SetUpTestSuite(),销毁对象后调用TearDownTestSuite()。测试程序不能修改共享资源的值,如果修改了值,在进行下一个测试之前需要复原。(为什么不能修改值)
    注意,SetUpTestSuite()TearDownTestSuite()可能会被多次调用(test fixture的派生类)

全局Set-Up和Tear-Down

如同在测试套层面设置SetUp和TearDown,可以在测试程序层面设置Set-Up和Tear-Down。

  1. 从::testing::Environment继承一个子类用来定义测试环境,
class Environment : public ::testing::Environment {
 public:
  ~Environment() override {}

  // Override this to define how to set up the environment.
  void SetUp() override {}

  // Override this to define how to tear down the environment.
  void TearDown() override {}
};
  1. 使用::testing::AddGlobalTestEnvironment()注册自定义的Environment 实例
Environment* AddGlobalTestEnvironment(Environment* env);
  • 完成上述两步后,当RUN_ALL_TESTS()被调用后,environment实例的SetUp()先运行,然后运行测试用例,最后调用TearDown()
  • 多个environment 实例也是允许的,它们的SetUp()也是按注册顺序被调用,TearDown()按相反的顺序调用。
  • GoogleTest 负责管理注册的environment的实例对象,所以用户不需要删除它们。
  • 应该在调用RUN_ALL_TESTS之前调用AddGlobalTestEnvironment, 可以定义一个全局变量如下:
testing::Environment* const foo_env =
    testing::AddGlobalTestEnvironment(new MyEnvironment);

Value-Parameterized测试

示例

先看测试代码,需要验证以下三个函数的返回值和1,2,3做对比

int test_p_func1() {
    return 1;
}

int test_p_func2() {
    return 2;
}

int test_p_func3() {
    return 3;
}

TEST 这样写

TEST(TestPFuncSuite, TestPFunc1) {
    EXPECT_EQ(test_p_func1(), 1);
    EXPECT_EQ(test_p_func1(), 2);
    EXPECT_EQ(test_p_func1(), 3);
    EXPECT_EQ(test_p_func2(), 1);
    EXPECT_EQ(test_p_func2(), 2);
    EXPECT_EQ(test_p_func2(), 3);
    EXPECT_EQ(test_p_func3(), 1);
    EXPECT_EQ(test_p_func3(), 2);
    EXPECT_EQ(test_p_func3(), 3);
}

这里因为不同的输入(要测试的接口)分别写了EXPECT_EQ,造成代码冗余,为避免这种情况,可以使用Value-parameterized tests。Value-parameterized tests可以通过不同的参数测试功能,避免因为不同的参数而要拷贝多个test body。用Value-parameterized tests可以按如下实现

class TableTestSample1 : public ::testing::TestWithParam<std::function<int()>> {
public:
    void SetUp() override {
        std::function<int()> f = GetParam();
        val_ = f();
    }
protected:
    int val_;
};
TEST_P(TableTestSample1, aaa) {
    EXPECT_EQ(1, val_);
    EXPECT_EQ(2, val_);
    EXPECT_EQ(3, val_);
}
INSTANTIATE_TEST_SUITE_P(MyTestPCase1, TableTestSample1, ::testing::Values(&test_p_func1, &test_p_func2, &test_p_func3));

如果test_p_func1带参数,可以通过std::bind将函数对象返回:::testing::Values(std::bind(&test_p_func1, param1, param2));

Value-Parameterized实现

分三步

  • 实现一个fixture类,这个类必须要继承自testing::Testtesting::WithParamInterface<T>,为简便起见,可以直接派生自testing::TestWithParam<T>testing::TestWithParam<T>派生自testing::Testtesting::WithParamInterface<T>)。注意:
    • T可以是任意可以拷贝的类型;
    • 如果T是一个裸指针类型,需要对其生命周期管理。
  • 使用TEST_P宏定义 test patterns,后缀_P 意思是 “parameterized” 或者 “pattern”,
  • 使用INSTANTIATE_TEST_SUITE_P 宏通过你指定的一系列参数实例化这个test suite。INSTANTIATE_TEST_SUITE_P在全局或namespace作用域中而非函数中。

INSTANTIATE_TEST_SUITE_P

参数:第一个参数是要实例化的 test suite的唯一名称;第二个参数为 test patterns名;第三个参数为parameter generator
INSTANTIATE_TEST_SUITE_P会用给定的参数实例化出一个test suite。
上述示例输出:
gtest之高级主题

类型测试

假设相同的接口,有不同的实现,想要确保他们满足相同的要求;或者定义了不同的类型,但是它们有着相同的概念要想验证,这两种情况下对不同的类型有着相同的测试逻辑,如果使用TEST 或者 TEST_F会显得相当冗长,此时可以使用typed tests。这里着重理解下不同的类型有相同的接口
实现步骤:

  1. 定义一个fixture模板类,继承自::testing::Test
  2. 使用宏TYPED_TEST_SUITE关联测试套和要测试的一系列类型,注意这里的类型别名是有必要的,便于TYPED_TEST_SUITE解析
using MyTypes = ::testing::Types<char, int, unsigned int>;
TYPED_TEST_SUITE(FooTest, MyTypes);
  1. 使用TYPED_TEST()代替TEST_F定义typed test suite

示例:

template<typename T>
class MyClass {
public:
    MyClass() = default;
    MyClass(const T &t): val_(t) { }
    T get_param() {
        return val_;
    }
    bool get_name() const {
        return true;
    }
private:
    T val_;
};
template<typename T>
class MyFixture : public ::testing::Test {
public:
    MyFixture() = default;
    void SetUp() override { }
protected:
    MyClass<T> p_;
};

using MyTypes = ::testing::Types<char, int, string>;
TYPED_TEST_SUITE(MyFixture, MyTypes);

TYPED_TEST(MyFixture, mytypedtest) {
    EXPECT_FALSE(this->p_.get_name());  // 注意,在test suite中要使用this访问Fixture中的变量
}

输出:
gtest之高级主题

和类型断言 ::testing::StaticAssertTypeEq<T1, T2>()的区别

Type-Parameterized Tests

类似于类型测试,但是不要求在测试之前就列出想要测试的类型。可以先写测试逻辑,然后再使用不同的类型实例化。可以在同一程序中多次实例化。
实现步骤:

  1. 定义fixture模板类,继承自::testing::Test
  2. 声明类型参数的test suite
  3. TYPED_TEST_P()实现
  4. 使用REGISTER_TYPED_TEST_SUITE_P 注册所有要测试的测试程序(第三步的实现),第一个参数是test suite名,其余名字为test name(即为3中的第二个参数)
  5. 实例化要测试的类型
using MyTypes = ::testing::Types<char, int, unsigned int>;
INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);

捕获失败

TODO

注册test程序

TODO

获取当前测试程序名

实际应用中可能需要知道当前运行的test name(比如要在test fixture的SetUp中获取),可以通过类TestInfo类来获取,要获取TestInfo对象,通过UnitTest单例的current_test_info()获取

  // 获取当前运行的测试的信息
  // 注意:不要删除获取到的这个对象,它由UnitTest 这个类管理
  const testing::TestInfo* const test_info =
      testing::UnitTest::GetInstance()->current_test_info();  // 如果没有测试运行则返回空指针

  printf("We are in test %s of test suite %s.\n",
         test_info->name(),
         test_info->test_suite_name());

通过test events扩展GoogleTest

GoogleTest提供了event listener API用来接收测试程序是测试失败的通知,这些events包括测试程序的开始和结束。你可以使用这些API增加或者替换标准控制台的输出,替换XML输出,或者提供一个完全不同格式的输出,如GUI或者数据库。

定义Event Listeners

自定义子类需要继承 testing::TestEventListener(这个是纯虚类)testing::EmptyTestEventListener.
当一个event被激活,上下文会传递一个handler function作为参数,这些参数类型为:

  • UnitTest:反映整个测试程序的状态
  • TestSuite:一个test suite的信息,包含一个或多个tests
  • TestInfo:包含测试状态
  • TestPartResult:测试断言的结果
    示例:
class MinimalistPrinter : public testing::EmptyTestEventListener {
    void OnTestStart(const testing::TestInfo& test_info) override {
        std::cout << "MinimalistPrinter: " << test_info.test_suite_name() << ' ' << test_info.name() << std::endl;
    }

    void OnTestPartResult(const testing::TestPartResult& test_part_result) override {
        printf("OnTestPartResult: %s in %s: %d\n%s\n", test_part_result.failed() ? "Failure" : " success",
                test_part_result.file_name(),
                test_part_result.line_number(),
                test_part_result.summary()
        );
    }

    void OnTestEnd(const ::testing::TestInfo& test_info) override {
        std::cout << "OnTestEnd: " << test_info.test_suite_name() << ' ' << test_info.name() << std::endl;
    }
};

使用Event Listeners

在main的RUN_ALL_TESTS()之前,添加event listener列表的实例:

int main(int argc, char **argv) {
    testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners();
    // delete listeners.Release(listeners.default_result_printer());
    listeners.Append(new MinimalistPrinter);
    testing::InitGoogleTest(&argc, argv);
    
    return RUN_ALL_TESTS();
}

有一个问题:默认的输出仍然是有效的,这样输出就会混杂在一起,可以通过添加上述第三行代码禁止默认输出,如下:
gtest之高级主题

  • 可以添加多个listener到列表中

在Listeners中生成失败

可以在处理event时使用断言宏,但有以下限制:

  1. 不能在OnTestPartResult()中生成失败,否则会引起OnTestPartResult的递归调用
  2. OnTestPartResult不允许产生任何失败

运行测试程序选项

可以通过环境变量或者命令行参数影响测试程序功能。为了支持命令行参数功能,必须在RUN_ALL_TESTS()之前调用::testing::InitGoogleTest()
可以通过在测试程序后加–help(或者-h, -?, /?)命令查看支持的选项
如果同时设置和环境变量和命令行参数命令,后者(命令行参数)将有优先权

选择性测试

  • 列出要测试的test suite和test name:命令行选项 --gtest_list_tests可以显示出所有要测试的test suite和test name,但不会运行。这个命令可以方便查看编译出来的测试程序支持哪些test suite和test name。显示格式如下:gtest之高级主题
  • 运行测试子集:gtest默认会运行所有的测试程序,如果只想运行其中的某一部分,可以设置环境变量 GTEST_FILTER 或者 命令行参数 --gtest_filter来设置过滤,gtest将会只运行名字符合过滤器的程序(格式为 TestSuiteName.TestName)。
    • ‘*’ 和 ‘?’ 通配符,匹配多个和一个
    • ‘:’ 表示或的关系,只要有一个的匹配都可以
    • ‘-’ 表示不匹配
./foo_test --gtest_filter=*Null*:*Constructor* 运行测试名字都包含"Null""Constructor"的test
./foo_test --gtest_filter=-*DeathTest.* 运行所有不包含DeathTest的测试
./foo_test --gtest_filter=FooTest.*-FooTest.Bar 运行除了FooTest.Bar之外的test suite为FooTest的测试
./foo_test --gtest_filter=FooTest.*:BarTest.*-FooTest.Bar:BarTest.Foo Runs everything in test suite FooTest except FooTest.Bar and everything in test suite BarTest except BarTest.Foo.
  • 第一次失败后停止测试:设置环境变量GTEST_FAIL_FAST或命令行参数--gtest_fail_fast可以在第一次测试失败后,停止后面的测试
    gtest之高级主题

  • 临时disable测试:如果有一些测试暂时不需要(有bug或者其他原因),使用注释或者预编译指令#if 0会让这些代码不被编译,可以在test suite名或者test name前加DISABLED_。(在test suite名或者test name前加效果一样)。

// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) { ... }
class DISABLED_BarTest : public testing::Test { ... };
// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) { ... }

gtest之高级主题

  • 临时启用disable的测试:通过设置命令函参数--gtest_also_run_disabled_tests或者环境变量GTEST_ALSO_RUN_DISABLED_TESTS 为非0就可以将上面用DISABLE_ 的test继续运行。再结合–gtest_filter可以选择哪些DISABLE的test运行

重复测试

偶现的问题可以通过重复多次测试复现,可以通过命令行参数 --gtest_repeat 或者环境变量 GTEST_REPEAT指定test methods运行多少次
--gtest_repeat=-1表示无限次执行
如果包含了全局的 set-up/tear-down,也是会重复执行,为了避免重复执行全局set-up/tear-down,使用--gtest_recreate_environments_when_repeating=false
测试输出(global没有重复执行):
gtest之高级主题

无序执行

测试套是按顺序执行的,如果想随机无序执行(比如为了测试某个不合理的依赖关系),可以指定命令行参数--gtest_shuffle或者环境变量GTEST_SHUFFLE
默认情况下gtest会根据当前时间计算出随机种子数,会在控制台上输出。为了复现某个失败的测试,可以通过--gtest_random_seed=SEED或者GTEST_RANDOM_SEED 指定随机种子值。随机种子数取值范围[0, 99999]。0代表GoogleTest 按默认当前时间计算seed值。如果将其与–gtest_repeat=N结合,GoogleTest将选择不同的随机种子,并在每次迭代中重新洗牌测试。
gtest之高级主题

分发到不同的机器

控制输出

  • 通过带颜色的终端输出可以比较清晰的分辨信息,可以通过GTEST_COLOR 或者命令行参数--gtest_color,取值为yes,no,auto(默认值)使能颜色或由gtest决定。
    – 实际使用没有效果
  • 简化测试结果:默认情况下一条测试会输出一条输出表明是否成功,通过命令行参数--gtest_brief=1或者将环境变量GTEST_BRIEF设置为1可以简化输出
    gtest之高级主题
  • 禁止显示时间:more情况下会显示运行每条test花费了多长时间,通过命令行参数--gtest_print_time=0或者将GTEST_PRINT_TIME 设置为0禁止显示
  • Suppressing UTF-8 Text Output
  • 生成XML报告:通过将环境变量GTEST_OUTPUT 或者命令行参数 --gtest_output设置为"xml:path_to_output_file",会将xml文件生成在指定位置。也可以直接设置为"xml",会在当前目录下输出test_detail.xml。如果指定目录如"xml:output/directory/",会在指定目录下生成 测试程序名.xml,如果文件存在,为避免覆盖,googletest会选择一个不同的名字如 测试程序名_1.xml。
  • 生成json报告:同生成xml,通过将环境变量GTEST_OUTPUT 或者命令行参数 --gtest_output设置为"json:path_to_output_file",也可以直接设置为"json",会在当前目录下输出test_detail.json。

Controlling How Failures Are Reported

  • 检测测试程序过早退出:gtest会在测试程序开始运行时创建文件,测试结束后删除文件。可以通过这种方式确认测试程序是否过早退出。这个功能只有在设置环境变量TEST_PREMATURE_EXIT_FILE 后生效。–未验证

结合Sanitizer

TODO
Undefined Behavior Sanitizer:https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
Address Sanitizer:https://github.com/google/sanitizers/wiki/AddressSanitizer
Thread Sanitizer:https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual文章来源地址https://www.toymoban.com/news/detail-435371.html

到了这里,关于gtest之高级主题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest

    目录 一、前言 二、从TEST宏开始 三、回过头看看TEST宏的定义 四、再来了解RUN_ALL_TESTS宏 四、总结 “深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节

    2024年02月11日
    浏览(40)
  • 玩转单元测试之gtest

    程序开发的时候,往往需要编写一些测试样例来完成功能测试,以保证自己的代码在功能上符合预期,能考虑到一些异常边界问题等等。 1.引入gtest 2.编写第一个单测 2.1 待测试文件 2.2 单测文件 2.3 makefile文件 make ./hello_unit_test 编译并执行单测程序,执行结果如下: 1. 各种断

    2024年02月12日
    浏览(25)
  • Linux 单元测试学习过程 (1)——gtest

    软件开发完成后需要对代码进行测试,生成测试报告,因此开始学习单元测试。本文基于QT和Linux进行学习。学习目的就是生成测试报告。整个学习过程主要围绕“1.怎么进行单元测试”、“2.怎么生成测试过程的结果文件”、“3.怎么生成代码覆盖率报告”。 1.使用gtest进行单

    2024年02月05日
    浏览(72)
  • C++单元测试Gtest+Stub攻略

    笔者环境为linux环境(deepin),以下均在此环境进行 Gtest源码链接 Stub源码链接 StubExt源码链接 Stub的使用方法在cpp-stub/README_zh.md中有讲解 StubExt的使用方法在 cpp-stub-ext/ README.md中有讲解 StubExt可支持Lambda表达式进行打桩写Gtest时如果想获取一个固定的返回值或者出参十分好用 搭建环

    2024年02月10日
    浏览(34)
  • cmake应用:集成gtest进行单元测试

    编写代码有bug是很正常的,通过编写完备的单元测试,可以及时发现问题,并且在后续的代码改进中持续观测是否引入了新的bug。对于追求质量的程序员,为自己的代码编写全面的单元测试是必备的基础技能,在编写单元测试的时候也能复盘自己的代码设计,是提高代码质量

    2024年02月13日
    浏览(32)
  • CMake项目使用ctest+gtest进行单元测试

    随着CMake工具越来越强大便捷,越来越多的C/C++项目转而使用CMake来进行编译管理,它还提供了用于测试的ctest命令来执行项目中编写的单元测试。 本文就以一个实例来介绍如何使用ctest来进行单元测试。 本文实例环境VSCode+MinGW64+CMake+gtest。 需要在MinGW中安装gtest,如果没有安装

    2024年02月05日
    浏览(32)
  • C++中的断言机制与gtest单元测试

       这部分内容网上已经有很多人讲了,我就不做重复性工作,制造垃圾了,大家看看下面两个链接就可以了,因为我的专栏除了分享自己学习的知识,主要想为大家提供完整学习路线,让大家的知识体系更加完善! (1)参考:https://www.cnblogs.com/lvchaoshun/p/7816288.html (1)参考:

    2023年04月08日
    浏览(88)
  • 基于gtest/gmock/mockcpp的单元测试探索

    本文整体内容参考https://www.cnblogs.com/heimianshusheng/p/13530672.html(后面统一称为\\\"引文\\\"),在实际调试中发现了一些问题并予以解决,记录一下方便自己和同道中人查阅。 通过实例演练学习使用gtest对C语言编写的程序进行单元测试 学习如何用mockcpp对C语言的函数进行mock *GitHub上的

    2023年04月21日
    浏览(30)
  • Ubuntu18.04环境下Gtest框架安装测试

    最新版本的Gtest下载链接:https://github.com/google/googletest 可以选择自己下载解压安装,下载的安装包为.ZIP文件时,下载unzip工具进行解压。 也可以创建一个文件夹使用命令行自动打包下载,一般习惯创建一个新的文件夹作为下载目录。 下载之后进入googletest文件夹,新建一个文

    2023年04月10日
    浏览(80)
  • 手把手教你使用gtest写单元测试

    开源框架:gtest,它主要用于写单元测试,检查真自己的程序是否符合预期行为。这不是QA(测试工程师)才学的,也是每个优秀后端开发codoer的必备技能。 本期博文内容及使用的demo,参考: Googletest Basic Guide[1] Googletest Samples [2] 构建依赖环境 按照惯例,先介绍下怎么基于

    2024年02月16日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包