• Google C++单元测试框架(Gtest)系列教程之五——再论测试固件


    引言

    《Google C++单元测试框架(Gtest)系列教程之三——测试固件(Test fixture)》中,介绍了如何使用测试固件为测试实例(Tests)进行数据配置和初始化。除了数据初始化方法,Gtest还提供了测试实例间共享数据的方法。

    同属一个测试用例的测试实例间共享数据

    为实现测试实例间的独立性,Gtest提供了为每个测试实例新生成一个测试固件对象的方法,通过“独享”测试对象中的数据,保证了一个测试实例的执行不会对其他实例的执行产生影响。但是,对于以下情况:

    1. 初始化数据涉及内存申请等操作,为每个测试实例构造对象将带来较大系统开销;
    2. 存在某数据,其在每个实例中均被用到,但每个实例都不会更改该数据的值;

    我们就没有必要将这些数据放入测试固件对象中了,在一个C++类中,使用什么方法能让数据独立于对象之外、又能被对象访问呢?


    没错!就是使用C++类的static成员变量,具体定义方法如下:

    1. 在测试固件类中,将需要在测试实例间共享的数据声明为static类型;
    2. 定义函数SetUpTestCase(),用于初始化共享数据;定义函数TearDownTestCase(),用于清理共享数据。这两个函数的函数类型均为static void。

    在测试程序执行时,Gtest在第一个测试实例运行之前调用SetUpTestCase(),在最后一个测试实例运行之后调用TearDownTestCase(),在此期间,测试实例可以使用所定义的共享数据。

    我们来看一个在测试实例间共享数据的实例:

    class FooTest : public ::testing::Test {
    protected:
    static void SetUpTestCase() {
    shared_resource_ = new ...;
    }
    static void TearDownTestCase() {
    delete shared_resource_;
    shared_resource_ = NULL;
    }
    // You can define per-test set-up and tear-down logic as usual.
    virtual void SetUp() { ... }
    virtual void TearDown() { ... }

    // Some expensive resource shared by all tests.
    static T* shared_resource_;
    };

    T* FooTest::shared_resource_ = NULL;

    TEST_F(FooTest, Test1) {
    ... you can refer to shared_resource here ...
    }
    TEST_F(FooTest, Test2) {
    ... you can refer to shared_resource here ...
    }

    由于Gtest不一定按照我们声明的顺序执行测试实例,因此我们的测试实例仍需保持独立,避免滥用共享数据造成的测试实例相互依赖的情况。在测试实例中,要不不改变共享数据的值,要不在改变数据值之后、执行完之前还原共享数据的值。

    程序级别数据共享

    正如前面介绍的,Gtest提供了测试实例(Tests)和测试用例(Test Case)级别的数据管理的方法,除此之外,Gtest在程序级别提供了共享数据管理方法,使得我们可以在测试用例和测试实例间共享数据。

    为实现在程序级别共享数据,首先我们需要定义一个继承自::testing::Environment的类,并且编写SetUp()和TearDown()函数覆盖父类中的相应虚函数,该类中的成员变量即可作为共享数据:

    class Environment {
    public:
    virtual ~Environment() {}
    // Override this to define how to set up the environment.
    virtual void SetUp() {}
    // Override this to define how to tear down the environment.
    virtual void TearDown() {}
    };

    其次,调用以下接口“注册”类对象:

    Environment* AddGlobalTestEnvironment(Environment* env);

    其参数为“注册”前的类对象指针,返回值为“注册”后的类对象指针。下面我们来看实例:

    class FooEnvironment: public testing::Environment
    {
    public:
    virtual void SetUp()
    {
    printf("Environment SetUp!\n");
    a = 100;
    }
    virtual void TearDown()
    {
    printf("Environment TearDown!\n");
    }
    int a;     //共享数据
    };
    FooEnvironment* foo_env;  //对象指针声明
    TEST(firstTest, first)    //访问共享数据并改变它的值
    {
    printf("in the firstTest, foo_env->p is %d\n", foo_env->a);
    foo_env->a ++;
    }
    TEST(secondTest, second)  //访问共享数据
    {
    printf("in the secondTest, foo_env->p is %d\n", foo_env->a);
    }
    int main(int argc, char* argv[])
    {
    foo_env = new FooEnvironment;
    testing::AddGlobalTestEnvironment(foo_env);     //注册
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
    }

    上面的测试用例firstTest和secondTest均访问了共享数据,作为演示,firstTest修改了共享数据的值。该测试程序执行结果如下:

    [==========] Running 2 tests from 2 test cases.
    [----------] Global test environment set-up.
    Environment SetUp!
    [----------] 1 test from firstTest
    [ RUN ] firstTest.first
    in the firstTest, foo_env->p is 100
    [ OK ] firstTest.first (0 ms)
    [----------] 1 test from firstTest (0 ms total)

    [----------] 1 test from secondTest
    [ RUN ] secondTest.second
    in the secondTest, foo_env->p is 101
    [ OK ] secondTest.second (0 ms)
    [----------] 1 test from secondTest (0 ms total)

    [----------] Global test environment tear-down
    Environment TearDown!
    [==========] 2 tests from 2 test cases ran. (0 ms total)
    [ PASSED ] 2 tests.


    小结

    在Gtest中,测试实例间共享数据的方式有两种(除全局变量的方式外),一种是让同属一个测试用例的测试实例间共享数据,另一种是可让程序中的所有测试实例共享数据。测试实例间进行数据共享,破坏了测试实例间执行的独立性,个人认为应该尽量避免使用。


    Reference: googletest project


  • 相关阅读:
    FSBQPIDMI总线的区别
    为什么PCI-e比SATA快这么多?
    chage命令管理用户口令时效
    账户管理groupadd groupmod groupdel usermod usermod userdel
    linux 里 /etc/passwd 、/etc/shadow和/etc/group 文件内容解释
    RPM常见用法
    智力逻辑题
    Android ROM 制作教程
    智能家居项目(2):项目project框架的搭建
    5999卖999!是噱头还是颠覆
  • 原文地址:https://www.cnblogs.com/bangerlee/p/2216006.html
Copyright © 2020-2023  润新知