http://www.cnblogs.com/coderzh/archive/2010/01/09/beautiful-testcase.html

使用gtest也有很长一段时间了,这期间也积累了一些经验,所以分享一下。GTest为我们提供了便捷的测试框架,让我们只需要关注案例本身。如何在GTest框架下写出优美的测试案例,我觉得必须要做到:

  1. 案例的层次结构一定要清晰
  2. 案例的检查点一定要明确
  3. 案例失败时一定要能精确的定位问题
  4. 案例执行结果一定要稳定
  5. 案例执行的时间一定不能太长
  6. 案例一定不能对测试环境造成破坏
  7. 案例一定独立,不能与其他案例有先后关系的依赖
  8. 案例的命名一定清晰,容易理解

案例的可维护性也是非常重要,如果做到上面的8点,自然也就做到了可维护性。下面来分享一下我对于上面8点的经验:

1. 案例的层次结构一定要清晰

所谓层次结构,至少要让人一眼就能分辨出被测代码和测试代码。简单的说,就是知道你在测什么。由于是进行接口测试,我已经习惯了如下的案例层次:

DataDefine

我会将测试案例所需要的数据,以及数据之间的联系全部在预先定义好。测试数据与案例逻辑的分离,有利于维护和扩展测试案例。同时,GTest先天就支持测试数据参数化,为测试数据的分离提供了进一步的便捷。什么是测试数据参数化?就是你可以预先定义好一批各种各样的数据,而你只需要编写一个测试案例的逻辑代码,gtest会将定义好的数据逐个套入测试案例中进行执行。具体的做法请见:玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化

SUT

SUT,即system under test,表明你的测试对象是什么,它可以是一个类(CUT),对象(OUT),函数(MUT),甚至可以是整个应用程序(AUT)。我单独将这个层次划分出来,主要有两个目的:

  • 明确的表示出你的测试对象是什么
  • 为复杂调用对象包装简单调用接口

明确表示测试对象是什么,便于之后对测试案例的维护和对测试案例的理解。同时,对于一些被测对象,你想要调用它需要经过一系列烦琐的过程,这时,就需要将这一烦琐的调用过程隐藏起来,而只关注被测对象的输入和输出。

TestCase

测试工程中,必须非常明确的表示出哪些是测试案例,哪些是其他的辅助文件。通常,我们会在测试案例的文件名加上Test前缀(或者后缀)。我建议,将所有的测试案例文件或代码放在最显眼的地方,让所有看到你的测试工程的人,第一眼看到的就是测试案例,这很重要。

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 = ;
int status = GetServiceStatus('xxx');
while (status != Running)
{
if (tryTimes >= )
break;
::Sleep();
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)

作者:CoderZhCoderZh的技术博客 - 博客园
微博:http://t.sina.com.cn/coderzh 
出处:http://coderzh.cnblogs.com
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

编写优美的GTest测试案例的更多相关文章

  1. gtest命令行测试案例

    使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便.同时,gtest也为我们提供了一系列的运行参数(环境变量.命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的 ...

  2. (转)编写Spring的第一个案例并测试Spring的开发环境

    http://blog.csdn.net/yerenyuan_pku/article/details/52832145 Spring4.2.5的开发环境搭建好了之后,我们来编写Spring的第一个案例 ...

  3. Storm自带测试案例的运行

    之前Storm安装之后,也知道了Storm的一些相关概念,那么怎么样才可以运行一个例子对Storm流式计算有一个感性的认识呢,那么下面来运行一个Storm安装目录自带的测试案例,我们的Storm安装在 ...

  4. Kafka吞吐量测试案例

    Kafka吞吐量测试案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 领英公司参考连接:https://www.slideshare.net/JiangjieQin/produc ...

  5. Hadoop基础-MapReduce入门篇之编写简单的Wordcount测试代码

    Hadoop基础-MapReduce入门篇之编写简单的Wordcount测试代码 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本文主要是记录一写我在学习MapReduce时的一些 ...

  6. Selenium私房菜系列5 -- 第一个Selenium RC测试案例

    <Selenium简介>中讲过,Selenium RC支持多种语言编写测试案例,如:C#,Python.在工作中,我倾向于是用Python这类动态语言编写测试案例,因为这样的测试案例无需编 ...

  7. Selenium(十四):自动化测试模型介绍、模块化驱动测试案例、数据驱动测试案例

    1. 自动化测试模型介绍 随着自动化测试技术的发展,演化为了集中模型:线性测试.模块化驱动测试.数据驱动测试和关键字驱动测试. 下面分别介绍这几种自动化测试模型的特点. 1.1 线性测试 通过录制或编 ...

  8. 实现如下类之间的继承关系,并编写Music类来测试这些类。

    实现如下类之间的继承关系,并编写Music类来测试这些类. package com.hanqi.test; public class Instrument { //输出弹奏乐器 public void ...

  9. mvn编写主代码与测试代码

    maven编写主代码与测试代码 3.2 编写主代码 项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包.默认情况下,Maven假设项目 ...

随机推荐

  1. java+ mysql 给所有的表添加假数据

    需求:别的项目, 代码扣过来了, 数据库也拿过来了, 但是数据库全是空表, 一共700 张表,需求是给表添加假数据,让它能运行起来. 一下是代码实现: 1.数据库连接: public static C ...

  2. qt优点

    (1)优良的跨平台特性.  Qt支持下列操作系统:Microsoft Windows 95/98.Microsoft Windows NT.Linux.Solaris.SunOS.HP-UX.Digi ...

  3. common-httpclient 用户名密码认证示例

    import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.com ...

  4. Linux Top 命令解析 比较详细--转

    TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中C ...

  5. XML的四种解析方式

    本文描述了构建良好的XML需要遵循的规则.作者详细介绍了构建XML需要考虑的元素,如何命名约定.正确的标记嵌套.属性规则.声明和实体,以及DTD和schema的验证,十分便于新手开始学习了解XML. ...

  6. [转] linux下的c/c++调试器gdb

    PS:1. 断点C++类函数,用b 命名空间::类名::方法名 2. 编译参数一定要加-g,才可断点调试 http://www.cnblogs.com/xd502djj/archive/2012/08 ...

  7. 使用ImageView

    @property (strong, nonatomic) UIPopoverController *pop; //选取图片- (IBAction)selectImage:(UIButton *)se ...

  8. C#学习第六天

    今天的内容主要是参数数组,C#允许函数指定一个(只能指定一个)特定的参数,这个参数必须是函数定义中最后一个参数,成为参数数组. 参数数组可以使用个数不定的参数调用函数,可以使用params关键字定义它 ...

  9. 关于iframe调用父页面元素操作

    在iframe子页面获取父页面元素 代码如下: //在iframe子页面获取父页面元素 $.('#objld', parent.document); //在父页面获取iframe子页面的元素 $(&q ...

  10. MySql Connector/Net Mysql like 搜索中文的问题(c#和asp.net连接mysql)

    Connector/Net 6.9.8 选择.net/mono即可,不需要安装. 将对应版本的MySql.Data.dll复制到bin目录下即可使用 http://dev.mysql.com/down ...