Checker
  对于一个复杂系统的接口测试,仅仅坚持输入和输出是远远不够的。比如测试一个写数据库的函数,函数的返回值告诉你数据已经成功写入是远远不够的,你必须亲身去数据库中查个究竟才行。因此,对于某一类的测试案例,我们可以抽象出一些通用的检查点代码。
  如果做到上面的分层,那么一个测试案例写出来的结构应该会是这个样子:
TEST(TestFoo, JustDemo)
{
GetTestData(); // 获取测试数据
CallSUT(); // 调用被测方法
CheckSomething(); // 检查点验证
}
  这样的测试案例,一目了然。
  2. 案例的检查点一定要明确
  一定要明确案例的检查点是什么,并且让检查点尽量集中。有一个不好的习惯是核心的检查点在分布在多个函数中,需要不断的跳转才能了解到这个案例检查了些什么。好的做法应该是尽量让检查点集中,能够非常清晰的分辨出案例对被测代码做了哪些检查。所以,尽量让Gtest的ASSERT_和EXPECT_系列的宏放在明显和正确的地方。
  3. 案例失败时一定要能精确的定位问题
  测试案例失败时,我们通常手忙脚乱。如果一个测试案例Failed,却不能立即推断是被测代码的Bug的话,这个测试案例也有待改进。我们可以在一些复杂的检查点断言中加入一些辅助信息,方便我们定位问题。比如下面这个测试案例:
int n = -1;
bool actualResult = Foo::Dosometing(n);
ASSERT_TRUE(actualResult)
  如果测试案例失败了,会得到下面的信息:
Value of: actualResult
Actual: false
Expected:true
  这样的结果对于我们来说,几乎没有什么用。因为我们根本不知道actualResult是什么,以及在什么情况下才会出现非预期值。因此,在断言处多加入一些信息,将有助于定位问题:
int n = -1;
bool actualResult = Foo::Dosometing(n);
ASSERT_TRUE(actualResult) << L"Call Foo::Dosometing(n) when n = " << n;
  4. 案例执行结果一定要稳定
  要保证测试案例在什么时候、什么情况下执行的结果都是一样的。一个一会成功一会失败的案例是没有意义的。要保证案例稳定性的方法有很多,比如杜绝案例之间的影响,有时候,由于前一个案例执行完后,将一些系统的环境破坏了,导致后面的案例执行失败。在测试某些本身存在一定几率或延时的系统时,使用超时机制是比较简单的办法。比如,你需要测试一个启动Windows服务的方法,如果我们在调用了该方法后立即进行检查,很可能检查点会失败,有时候也许又是通过的。这是因为Windows服务由Stop状态到Running状态,中间还要经过一个Padding状态。所以,简单的做法是使用超时机制,隔断时间检查一次,直到超过某个大忍受时间。
ASSERT_TRUE(StartService('xxx'));
int tryTimes = 0;
int status = GetServiceStatus('xxx');
while (status != Running)
{
if (tryTimes >= 10)
break;
::Sleep(200);
tryTimes++;
status = GetServiceStatus('xxx');
}
ASSERT_EQ(Running, status) << "Check the status after StartService('xxx')";
  5. 案例执行的时间一定不能太长
  我们应该尽量让案例能够快速的执行,一方面,我们可以通过优化我们的代码来减少运行时间,比如,减少对重复内容的读取。一方面,对于一些比较耗时的操作,比如文件系统,网络操作,我们可以使用Mock对象来替代真实的对象。使用GMock是一个不错的选择。
  6. 案例一定不能对测试环境造成破坏
  有的案例需要在特定的环境下来能执行,因此会在案例的初始化时对环境进行一些修改。注意,不管对什么东西进行了修改,一定要保证在案例执行完成的TearDown中将这些环境都还原回来。否则有可能对后面的案例造成影响,或者出现一些莫名其妙的错误。
  7. 案例一定独立,不能与其他案例有先后关系的依赖
  任何一个案例都不依赖于其他测试案例,任何一个案例的执行结果都不应该影响到别的案例。任何一个案例都可以单独拿出去正确的执行。所以,不能寄希望于前一个案例所做的环境准备,因为这是不对的。
  8. 案例的命名一定清晰,容易理解
  案例的名字要规范,长不要紧,一定要清晰的表达测试案例的用途。比如,下面的测试案例名称都是不好的:
TEST(TestFoo, Test)
TEST(TestFoo, Normal)
TEST(TestFoo, Alright)
  比如像下面的案例名称会好一点:
TEST(TestFoo, Return_True_When_ParameterN_Larger_Then_Zero)
TEST(TestFoo, Return_False_When_ParameterN_Is_Zero)