本文参考
1. 最简单的测试
以下代码来源于gtest的示例代码
samples\sample1_unittest.cc
int Factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
TEST(FactorialTest, Negative) {
// This test is named "Negative", and belongs to the "FactorialTest"
// test case.
EXPECT_EQ(1, Factorial(-5));
EXPECT_EQ(1, Factorial(-1));
EXPECT_GT(Factorial(-10), 0);
}
gtest实现测试功能,就是使用宏 TEST
来定义一个结构 这个宏包含三部分
- 测试类名: “FactorialTest”
- 测试方法名:“Negative”
- 测试方法体:“EXPECT_EQ(1, Factorial(-5));......”
测试方法中通过比较实际值与期望值之间的关系来确定所需测试对象是否正常工作,例如判断函数返回值等。
为此gtest 提供了一系列断言宏。帮助用户判断一系列状态。
总体上宏宏分为ASSERT系列与EXPECT系列
- ASSERT_* 断言系列。当检查点失败时,退出当前函数。不执行后续检测点
- EXPECT_*期望系列。当检查点失败时,继续执行后续检查点。
gtest 将断言宏进行了分类
1.1. 真假检查
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
1.2. 比较检查
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_EQ(val1,val2); | EXPECT_EQ(val1,val2); | val1 == val2 |
ASSERT_NE(val1,val2); | EXPECT_NE(val1,val2); | val1 != val2 |
ASSERT_LT(val1,val2); | EXPECT_LT(val1,val2); | val1 < val2 |
ASSERT_LE(val1,val2); | EXPECT_LE(val1,val2); | val1 <= val2 |
ASSERT_GT(val1,val2); | EXPECT_GT(val1,val2); | val1 > val2 |
ASSERT_GE(val1,val2); | EXPECT_GE(val1,val2); | val1 >= val2 |
1.3. 字符串检查
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(str1,str2); | EXPECT_STREQ(str1,_str_2); | the two C strings have the same content |
ASSERT_STRNE(str1,str2); | EXPECT_STRNE(str1,str2); | the two C strings have different content |
ASSERT_STRCASEEQ(str1,str2); | EXPECT_STRCASEEQ(str1,str2); | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1,str2); | EXPECT_STRCASENE(str1,str2); | the two C strings have different content, ignoring case |
为了更加清晰的认识各部分的意义,展开了宏定义,得到如下代码。
vs2012 生成预处理文件方法为选择源文件
属性→c++→预处理器→预处理到文件→是(/P)
预处理取消显示行号→是(/EP)
宏定义展开结果
class FactorialTest_Negative_Test : public ::testing::Test {
public:
FactorialTest_Negative_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo* const test_info_ ;
FactorialTest_Negative_Test(FactorialTest_Negative_Test const &);
void operator=(FactorialTest_Negative_Test const &);
};
::testing::TestInfo* const FactorialTest_Negative_Test ::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "FactorialTest", "Negative", 0, 0, ::testing::internal::CodeLocation("samples\\sample1_unittest.cc", 79), (::testing::internal::GetTestTypeId()), ::testing::Test::SetUpTestCase, ::testing::Test::TearDownTestCase, new ::testing::internal::TestFactoryImpl< FactorialTest_Negative_Test>);
void FactorialTest_Negative_Test::TestBody() {
switch (0)
case 0:
default:
if (const ::testing::AssertionResult gtest_ar = (::testing::internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(1)) == 1)>::Compare("1", "Factorial(-5)", 1, Factorial(-5)))) ;
else
::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "samples\\sample1_unittest.cc", 82, gtest_ar.failure_message()) = ::testing::Message();
switch (0)
case 0:
default:
if (const ::testing::AssertionResult gtest_ar = (::testing::internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(1)) == 1)>::Compare("1", "Factorial(-1)", 1, Factorial(-1)))) ;
else
::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "sample1_unittest.cc", 83, gtest_ar.failure_message()) = ::testing::Message();
switch (0)
case 0:
default:
if (const ::testing::AssertionResult gtest_ar = (::testing::internal::CmpHelperGT("Factorial(-10)", "0", Factorial(-10), 0))) ;
else
::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "samples\\sample1_unittest.cc", 84, gtest_ar.failure_message()) = ::testing::Message();
}
从展开结果可以看出最终测试方法生成了一个
测试类名_测试方法名_Test的类
该类包含:
public的构造函数
禁用了拷贝构造函数与‘=’
静态变量 test_info_
重载函数虚函数 TestBody
测试方法体被展开为TestBody
2. 包含初始化的测试
使用过JUnit测试的知道JUnit测试运行包含
- @BeforeClass setUpBeforeClass()
- @Before setUp()
- test()
- @After tearDown()
- @AfterClass tearDownAfterClass()
gtest 也支持类似操作
以下例子来自于
samples\sample5_unittest.cc
class QuickTest : public testing::Test {
protected:
virtual void SetUp() {
start_time_ = time(NULL);
test = 0;
}
virtual void TearDown() {
const time_t end_time = time(NULL);
EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
}
time_t start_time_;
int test ;
};
TEST_F(QuickTest, test) {
EXPECT_EQ(start_time_,start_time_);
}
宏展开如下
class QuickTest : public testing::Test {
protected:
virtual void SetUp() {
start_time_ = time(0);
test = 0;
}
virtual void TearDown() {
const time_t end_time = time(0);
switch (0)
case 0:
default:
if (const ::testing::AssertionResult gtest_ar_ = ::testing::AssertionResult((end_time - start_time_ <= 5))) ;
else ::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "\\sample5_unittest.cc", 81, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_, "end_time - start_time_ <= 5", "false", "true").c_str()) = ::testing::Message() << "The test took too long.";
}
time_t start_time_;
int test ;
};
class QuickTest_test_Test : public QuickTest {
public:
QuickTest_test_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo* const test_info_ ;
QuickTest_test_Test(QuickTest_test_Test const &);
void operator=(QuickTest_test_Test const &);
};
::testing::TestInfo* const QuickTest_test_Test ::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "QuickTest", "test", 0, 0, ::testing::internal::CodeLocation("\\sample5_unittest.cc", 89), (::testing::internal::GetTypeId<QuickTest>()), QuickTest::SetUpTestCase, QuickTest::TearDownTestCase, new ::testing::internal::TestFactoryImpl< QuickTest_test_Test>);
void QuickTest_test_Test::TestBody() {
switch (0)
case 0:
default:
if (const ::testing::AssertionResult gtest_ar = (::testing::internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(start_time_)) == 1)>::Compare("start_time_", "start_time_", start_time_, start_time_))) ;
else ::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "\\sample5_unittest.cc", 91, gtest_ar.failure_message()) = ::testing::Message();
}
这个示例代码更好的体现出了测试类,测试方法之间的继承关系
一个测试类包含多个测试方法,每个测试方法在执行前都先执行SetUpTestCase()然后执行TestBody()最后执行TearDownTestCase()
在实际测试中可以利用SetUpTestCase执行初始化,TearDownTestCase完成资源回收。确保每个案例相互独立,不相互受影响。
__注意:带有测试类的方法使用的宏是 TEST_F 不是 TEST __
3. 类级别共享数据
与JUnit一样类级别共享的数据使用静态变量实现,初始化在static void SetUpTestCase()
完成,释放在static void TearDownTestCase()
完成
4.参数化测试
要实现参数化测试需要声明类并继承testing::TestWithParam<T>
类,或testing::WithParamInterface<T>
二者关系为
template <typename T>
class TestWithParam : public Test, public WithParamInterface<T> {
};
参数化列表使用如下方法初始化
INSTANTIATE_TEST_CASE_P(TestState, DoubleStateTest, ::testing::Values(-1.0,0.0,1,0));
第一个参数是测试案例的前缀,可以任意取
第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同
第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:
函数名 | 说明 |
---|---|
Range(begin, end[, step]) | 范围在begin~end之间,步长为step,不包括end |
Values(v1, v2, ..., vN) | v1,v2到vN的值 |
ValuesIn(container) and ValuesIn(begin, end) | 从一个C类型的数组或是STL容器,或是迭代器中取值 |
Bool() | 取false 和 true 两个值 |
Combine(g1, g2, ..., gN) | 将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。 |
运行参数化如下,GetParam()方法会依次返回参数列表中的参数
TEST_P(DoubleStateTest,TestGetDouble)
{
doule state = GetParam();
}
注意: 参数化测试宏为 TEST_P
4. 一点示例
在我实现的测试方法中就存在如下关系。目的是合理组织测试用例。使得整个测试看起来有序。
//basetest.h
class BaseTest : public testing::Test{
public:
static void SetUpTestCase() {
m_pEngine = new MapEngine();
}
static void TearDownTestCase() {
delete m_engine;
m_engine = NULL;
}
public:
static MapEngine* m_pEngine;
};
//basetest.cpp
MapEngine BaseTest::m_pEngine= NULL;
//muictest.cc
class MiscTest : public BaseTest
{
public:
virtual void SetUp()
{
m_pEngine->SetUp();
}
virtual void TearDown()
{
m_pEngine->TearDown();
}
};
//需要参数化测试的案例
class BoolStateTest : public BaseTest,
public testing::WithParamInterface<bool>{
}
5. 运行测试
在main 函数中
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
这样即可执行所有测试
6. 运行参数
输出xml
--gtest_output=xml:_path_to_output_file_