引言
在《Google C++单元测试框架(Gtest)系列教程之三——测试固件(Test fixture)》中,介绍了如何使用测试固件为测试实例(Tests)进行数据配置和初始化。除了数据初始化方法,Gtest还提供了测试实例间共享数据的方法。
同属一个测试用例的测试实例间共享数据
为实现测试实例间的独立性,Gtest提供了为每个测试实例新生成一个测试固件对象的方法,通过“独享”测试对象中的数据,保证了一个测试实例的执行不会对其他实例的执行产生影响。但是,对于以下情况:
- 初始化数据涉及内存申请等操作,为每个测试实例构造对象将带来较大系统开销;
- 存在某数据,其在每个实例中均被用到,但每个实例都不会更改该数据的值;
我们就没有必要将这些数据放入测试固件对象中了,在一个C++类中,使用什么方法能让数据独立于对象之外、又能被对象访问呢?
没错!就是使用C++类的static成员变量,具体定义方法如下:
- 在测试固件类中,将需要在测试实例间共享的数据声明为static类型;
- 定义函数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.
小结