遇见gtest--事件
2015-11-02 20:52
363 查看
1、前言
在单元测试中,我们经常需要在某个测试套件、测试用例或者整个测试运行之前进行前置条件设置及检查,或者运行之后对运行结果进行校验等操作。在gtest中,称之为事件机制。gtest将事件按照作用的范围不同进行划分,从大到小总共分为3个层次:
1)整个测试层面,即在测试工程开始前和结束后进行;
2)测试套件层面,即在某个测试套件开始前和结束后进行;
3)测试用例层面,即在某个测试用例开始前和结束后进行;
2、测试层面事件实现
要实现测试层面的事件,我们需要继承testing::Environment类,首先我们来看一下这个类的定义:
这个类中有两个虚函数:SetUp和TearDown。我们的子类只需要实现这个方法即可。其中在SetUp方法中实现所有测试启动之前需要完成的操作,而TearDown函数中实现所有测试运行结束后需要进行的操作。例如:
然后,在main函数中,在RUN_ALL_TESTS()之前,我们调用如下语句:
testing::AddGlobalTestEnvironment(new GlobalEnvent);
将这个测试层面的的事件添加到事件列表即可。这样,在测试执行之前,系统会先执行GlobalEvent2的SetUp方法;在所有测试用例执行完之后,系统会执行GlobalEvent2的TearDown方法。另外,我们可以定义任意多个继承自testing::Environment的子类,以实现不同的全局事件。所有的子类的SetUp按照我们调用testing::AddGlobalTestEnvironment添加它们的先后顺序执行,而TearDown的执行顺序则与添加顺序相反。
3、测试套件层面事件
要在测试套件层面上定义事件,我们需要继承testing::Test类,并覆盖它的静态方法:SetUpTestCase和TearDownTestCase.在继续之前我们首先看看testing::Test类的定义:
从testing::Test类的声明可以看到,SetUpTestCase和TearDownTestCase为静态方法,并且它们的注释也很详细。在测试套件的第一个测试用例开始前,SetUpTestCase函数会被调用,而在测试套件中的最后一个测试用例运行结束后,TearDownTestCase函数会被调用。
4、测试用例层面的事件
要实现单个测试用例的事件,我们需要同样需要继承testing::Test类,并实现它的protected virtual方法SetUp和TearDown。gtest在运行这个测试用例之前,会首先调用SetUp方法,然后在测试用例结束之后,调用TearDown方法。
5、总结
通过gtest事件机制,我们可以让gtest在运行测试、测试套件、测试用例的前后分别运行指定的代码段。这一点很有用,比如在单元测试中,我们可以将初始化操作放入SetUp函数中,而资源回收等操作方在TearDown函数中实现,这样可以使得我们在测试用例中只需专注于测试即可。
在单元测试中,我们经常需要在某个测试套件、测试用例或者整个测试运行之前进行前置条件设置及检查,或者运行之后对运行结果进行校验等操作。在gtest中,称之为事件机制。gtest将事件按照作用的范围不同进行划分,从大到小总共分为3个层次:
1)整个测试层面,即在测试工程开始前和结束后进行;
2)测试套件层面,即在某个测试套件开始前和结束后进行;
3)测试用例层面,即在某个测试用例开始前和结束后进行;
2、测试层面事件实现
要实现测试层面的事件,我们需要继承testing::Environment类,首先我们来看一下这个类的定义:
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() {} private: struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } };
这个类中有两个虚函数:SetUp和TearDown。我们的子类只需要实现这个方法即可。其中在SetUp方法中实现所有测试启动之前需要完成的操作,而TearDown函数中实现所有测试运行结束后需要进行的操作。例如:
class GlobalEvent2 : public testing::Environment { public: virtual void SetUp() { cout << "Before any case, Global 2" << endl; } virtual void TearDown() { cout << "After all cases done, Global 2" << endl; } };
然后,在main函数中,在RUN_ALL_TESTS()之前,我们调用如下语句:
testing::AddGlobalTestEnvironment(new GlobalEnvent);
将这个测试层面的的事件添加到事件列表即可。这样,在测试执行之前,系统会先执行GlobalEvent2的SetUp方法;在所有测试用例执行完之后,系统会执行GlobalEvent2的TearDown方法。另外,我们可以定义任意多个继承自testing::Environment的子类,以实现不同的全局事件。所有的子类的SetUp按照我们调用testing::AddGlobalTestEnvironment添加它们的先后顺序执行,而TearDown的执行顺序则与添加顺序相反。
3、测试套件层面事件
要在测试套件层面上定义事件,我们需要继承testing::Test类,并覆盖它的静态方法:SetUpTestCase和TearDownTestCase.在继续之前我们首先看看testing::Test类的定义:
class GTEST_API_ Test { public: friend class TestInfo; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the <testcase> element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding <testsuite> element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the <testsuites> element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); };
从testing::Test类的声明可以看到,SetUpTestCase和TearDownTestCase为静态方法,并且它们的注释也很详细。在测试套件的第一个测试用例开始前,SetUpTestCase函数会被调用,而在测试套件中的最后一个测试用例运行结束后,TearDownTestCase函数会被调用。
4、测试用例层面的事件
要实现单个测试用例的事件,我们需要同样需要继承testing::Test类,并实现它的protected virtual方法SetUp和TearDown。gtest在运行这个测试用例之前,会首先调用SetUp方法,然后在测试用例结束之后,调用TearDown方法。
5、总结
通过gtest事件机制,我们可以让gtest在运行测试、测试套件、测试用例的前后分别运行指定的代码段。这一点很有用,比如在单元测试中,我们可以将初始化操作放入SetUp函数中,而资源回收等操作方在TearDown函数中实现,这样可以使得我们在测试用例中只需专注于测试即可。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性
- C++ Custom Control控件向父窗体发送对应的消息