文档库 最新最全的文档下载
当前位置:文档库 › 如何进行灰盒测试

如何进行灰盒测试

如何开展灰盒测试

灰盒测试优缺点分析

★几个基本概念

首先,把一些基本概念,简单通俗地说一下。如果觉得俺解释得不够好,不够细,可以自己去查维基百科的词条:洋文的在“这里”,中文的词条在“这里”(可惜中文词条不够全,偏偏缺了“灰盒测试”这一节)。

◇黑盒测试

通俗来说:黑盒测试不关注软件内部的实现细节。他仅仅把被测试的软件当成一个整体来处理,只关注软件的外在表现,不关注内部细节。典型的黑盒测试,就是光拿着鼠标操作一下用户界面,看看功能是否满足要求。

◇白盒测试

白盒测试与黑盒测试相反,重点关注软件内部的实现细节(比如代码覆盖率等)。

◇灰盒测试

如果你是从事开发或者测试的行当,应该已经听过黑盒测试与白盒测试这2个概念。但对灰盒测试,或许比较耳生。单纯从名称上来看,灰盒测试是介于黑盒测试与白盒测试之间的一种测试方式。

这种测试方式,主要用于多模块构成的稍微复杂的软件系统。在灰盒测试中,重点关注软件系统的各个组成模块之间的互动。这里所说的"互动",包括模块之间的互相调用、数据传递、同步/互斥、等等。

◇灰盒测试与黑盒测试的区别

如果某软件包含多个模块,当你使用黑盒测试时,你只要关心整个软件系统的边界,无需关心软件系统内部各个模块之间如何协作。而如果使用灰盒测试,你就需要关心模块与模块之间的交互。这是灰盒测试与黑盒测试的区别。

◇灰盒测试与白盒测试的区别

但是,在灰盒测试中,你还是无需关心模块内部的实现细节。对于软件系统的内部模块,灰盒测试依然把它当成一个黑盒来看待。而白盒测试则不同,还需要再深入地了解内部模块的实现细节。所以,这是灰盒测试与黑盒测试的区别。

◇灰盒测试与单元测试的区别

刚才看到有网友在评论中问到此问题,俺补充一下。

首先,在进行单元测试时,需要写一些测试代码(行话叫“桩代码”,洋文叫stub)。通常测试代码和被测试代码通常是同种语言(比如Java的单元测试通常也用Java来写),且测试代码和被测试代码的耦合很紧密。因此,单元测试通常由开发人员来完成的,测试人员的能力未必能胜任。

其次,单元测试的颗粒度会更细(会细到类一级、函数一级),而灰盒测试仅仅到模块一级。

★相对于黑盒测试的优点

灰盒测试相对黑盒测试的优点,其实有不少,俺挑几个重要的来说说。

◇测试可以及早介入

由于黑盒测试把整个软件系统当成一个整体来测试。如果系统的某个关键模块还没有完工,那测试人员就无法对整个系统进行测试,只好闲着没事干。而灰盒测试是针对模块的边界进行,模块开发完一个就测试一个。

◇有助于测试人员理解系统结构

为了进行灰盒测试,测试人员首先要熟悉内部模块之间的协作机制。在熟悉的过程中,“顺便”也就对整个系统(及其结构)有一个初步的、宏观的认识。这有助于测试人员发现一些系统结构方面的Bug。

而对于黑盒测试来说,由于测试人员不清楚软件系统的内部结构,难以发现一些结构性的缺陷。

◇有助于管理层了解真实的开发进度

一些复杂的大系统,经常会发生开发进度失控的情况。因为很多开发人员有报喜不报忧的倾向。当某个开发人员号称自己的工作已经完成了90%,往往意味着他/她还要花同样多的时间来完成剩下的10%。这导致负责项目管理的人,无法了解开发的真实进度。

由于灰盒测试针对对每一个模块进行,而且测试人员会从一个客观的角度来反馈模块的完成情况,这非常有利于管理层了解整个系统的真实完成情况。

◇可以构造更好的测试用例

如果仅仅用黑盒的方式测试系统的外部边界(通常是用户界面),有很多软件缺陷是不容易发现的。俺分别以B/S系统和C/S系统来举例。

假设开发一个复杂的(Windows环境下的)C/S软件。那么,这个软件通常不会仅仅只有一个EXE文件。它可能会有若干个EXE文件以及若干个DLL文件。假如某个DLL 提供的导出函数,没有按照约定对输入参数进行有效性判断(比如指针是否为空),那你用黑盒测试的方式,难以暴露出这种缺陷。而灰盒测试就容易发现此类问题(具体如何发现,后续的帖子会细说)。

假如你开发的是一个Web应用系统,那么,这种系统的服务端多半会提供若干个Web 接口用于被客户端调用。假如某个Web接口存在安全性问题/并发性问题/健壮性问题/XX 问题,你单纯用黑盒测试的手段,同样难以发现,而灰盒测试就可以搞定(灰盒测试是如何搞定的,后续帖子会细说)。

◇利于提升测试人员能力

很多公司搞的黑盒测试,就是让测试人员用鼠标(键盘都难得用)操作用户界面。在这种的环境里,测试人员干的活,很多都是重复性的体力劳动,技术能力难以得到提高。

而如果搞灰盒测试,测试人员就需要多懂一点技术背景知识,必要时还得写点测试脚本,对测试人员的能力提升很有好处。

★相对于白盒测试的好处

灰盒测试相对白盒测试的好处,比较容易概括。简单来说,就是白盒测试较费钱(研发

成本较高)。这多出来的研发成本,体现在如下几个方面。

◇首先,招聘成本较高

在人才市场上,100个应聘的测试人员中,未必能够找到一个合适的白盒测试人员。至少从俺及周围同事的面试经历来看,难得碰到具备白盒测试能力的人。所以,你可能要花很长时间才能找到合适的人,时间成本浪费掉了。

◇其次,培训成本较高

可能有同学会说,招不到就内部培养呗。这个说起来容易,但是培训也是有成本的。而且周期还不短,同样要耗费时间成本。

◇再其次,人力成本较高

物以稀为贵是一条普遍的经济学规律。由于能搞白盒测试的家伙是稀有动物,你自然不能给他/她开太低的薪水。否则人家待不了多久就跑路了。薪水开得高了,人力成本自然也就提高了。

★其它的一些好处

前面拿灰盒测试分别跟黑盒/白盒进行了对比,列举了一些优点。还有另外一些优点,和黑盒/白盒没啥关系,单独列在这里。

◇顺便强化开发文档

对于一个复杂的软件系统,模块之间的接口是很重要的,因此捏,接口文档也是很重要滴。而开发人员不爱写文档/不爱更新文档,(在软件业内)已经是臭名昭著了。很多软件开发到后期,模块之间的接口文档要么没有,要么和代码实现严重脱节。

但是,如果引入测试人员对模块之间的接口进行测试,就可以有效防止此种弊端。因为测试人员在测试前,首先要看模块间的接口文档,然后再根据接口文档设计测试用例,最后再执行用例。因此,一旦接口文档和代码实现不符,立马就露馅了。

◇顺便搞搞自动化

灰盒测试如果落实到位,还可以跟自动化测试相结合。从此可以大大提升测试的效率,进而大大提升软件的质量。(如何进行自动化的灰盒测试,后面的帖子会细谈)

★灰盒测试有啥缺点?

当然,凡事都有优点和缺点,灰盒测试自然也不例外。下面列举它的主要缺点。

◇不适用于简单的系统

所谓的简单系统,就是简单到总共只有一个模块。由于灰盒测试关注于系统内部模块之间的交互。如果某个系统简单到只有一个模块,那就没必要进行灰盒测试了。

◇对测试人员的要求比黑盒测试高

从上面的介绍来看,灰盒测试要求测试人员清楚系统内部由哪些模块构成,模块之间如何协作。因此,对测试的要求就提高了。因此,会带来一定的培训成本。不过捏,依照俺的经验,培训难度不大。稍微有点基础的测试人员,都可以在短期培训之后胜任。

◇不如白盒测试深入

显然,灰盒不如白盒那么深入。不过捏,考虑到灰盒测试相比白盒测试有显著的成本优势,该缺点不是太明显。

★总结

总而言之,言而总之,灰盒测试是一个很不错的东东,其优点明显而缺点容易克服。另外,俺前后在两家公司的研发部门推行过,效果不错的说。大伙儿值得去尝试一下。今天光说了优缺点对比,在管理层面和技术层面,具体该如何落实?

。当你企图推行某个东东的时候,真正的障碍往往是管理上的,而不是技术上的。所以,今天先介绍一下,推行灰盒测试之前,需要进行哪些管理上的准备工作。

管理方面的准备工作

★观念上的改变

可能是因为黑盒测试应用太广的缘故,导致很多开发人员和测试人员认为黑盒测试就是测试的全部。由于黑盒测试关注的是软件系统的外部边界。在大多数的软件公司里,软件的外部边界主要就是用户界面。这就造成了一个误区:把软件测试和用户界面测试等同起来。

如果开发人员持有这个错误观念,他/她就把精力放在:如何让软件的界面操作正常。至于软件的内部模块,其接口是否正常、协同是否正常,就不太关注了。用某些开发人员的话来讲,就是:“软件只要能貌似正常地工作,就行了”。

同样的,如果测试人员持有这样的观念,他/她就仅仅去测试软件的外部边界(比如用户界面),而毫不关心软件内部模块的问题。

在这种误区的影响下,最终发布出来的软件产品,多半是“金玉其外、败絮其中”。所以,在管理上,要通过各种方式,首先改变这种错误的观念,让开发人员和测试人员都注重内部模块的协同问题。

★设计上的改变

说完观念上的改变,再来谈谈设计上的改变。

大部分开发人员在设计内部模块的接口时,往往只考虑开发上的便利,而不考虑测试上的便利。结果捏,软件开发完之后,测试人员在进行模块接口的测试时,会非常费力,甚至无从下手。所以,俺在进行模块接口的设计评审时,会非常强调“可测试性”的考虑。

◇以动态库接口为例

当你用C++开发一个动态库时,对于动态库的导出函数可以有两种风格:C++风格和纯C风格(extern "C")。在俺负责的产品中,动态库的接口设计通常要求用纯C风格的导出函数。抛开各种高深的设计理念不谈(这不是今天的重点),单纯考虑“可测试性”,纯C风格的函数接口非常方便测试。很多时候,测试用一些简单的脚本,就可以对“纯C风格”的导出函数进行测试。具体如何做,下一帖会具体介绍。

◇以Web接口为例

考虑到有些网友不是搞C/S开发的(尤其不是搞C++的),可能看不懂上述例子。俺再举一个Web接口的例子。

和动态库的接口风格类似,Web接口也有两种常见的风格:SOAP和REST(两者的介绍参见“这里”和“这里”)。同样的,俺比较倾向于使用REST风格。抛开其它的优缺点不谈,单纯从“可测试性”来看,REST的优势非常明显——更简单、更可读。

★文档上的改变

由于灰盒测试侧重于内部模块的接口测试,因此接口文档就显得非常重要了。模块的其它文档可以省略,但是模块的接口文档是一定不能马虎的。接口文档不光是开发人员与开发人员之间的契约,而且是开发人员与灰盒测试人员之间的契约。这玩意儿的重要性,无须多说,想必大伙儿也应该明白。

由于很多开发人员不愿意/不屑于写文档,还有一些开发人员是在编码完成之后,再补文档。这些都对灰盒测试的开展很不利。如果没有彻底改变,灰盒测试很难开展。

对于接口文档的要求,俺主要强调两点:一个是文档的内容,一个是完成文档的时间点。

◇接口文档的内容

接口文档在内容上一定要简洁、实用,而且要确保测试人员能看懂——毕竟测试人员的技术水平不如开发人员那么高。另外,不同类型的接口,会有不同的接口文档形式,俺会在后面的帖子里面详细介绍。

◇接口文档的完成时间

关于时间点,俺的做法是:在内部模块的编码之前,一定要先让开发人员把接口文档写出来,并经过评审。

这么做不光对开发有好处,对测试也很有好处。当接口文档完成后,开发人员开始Coding的时候,测试人员也可以同步进行测试用例及测试脚本的编写。这就尽可能地实现了开发工作和测试工作的并行。

★测试团队的改变

前面说的设计问题和文档问题,都是开发人员的事情,那测试人员这边,需要做出哪些改变捏?主要的一条是人员结构的改变。以俺的经验,在测试团队中,要安排1/4~1/3的人员全力负责灰盒测试。因此,在开展灰盒测试之前,先要通过内部培养或外部招聘的方式,落实有能力的测试人员,来担此重任。

前一个帖子,俺曾经说过,灰盒测试的培训成本/招聘成本介于黑盒与白盒之间。那么,俺就大致说一下,对负责灰盒测试的人员,大致有哪些技能方面的要求。事先声明:灰盒测试的技能要求,与要测试软件密切相关;以下列出的技能要求,来自俺本人的经验,肯定不全面,仅供参考。

◇通用技能

首先,要有初步的编程基础:至少得懂得循环语句、判断语句、算术表达式、逻辑表达式、函数调用等最基本的东东。考虑到多年来,高校的计算机系一直在扩招,很多测试人员都曾经在计算机系呆过,窃以为不难达到这个水平。

最好掌握一门功能较强的脚本语言。按照俺的习惯,首先推荐Python(俺还专门写了一个Python扫盲的系列教程,在“这里”);当然,Perl、Lua也可以考虑;如果你测试的软件仅限于Windows平台,PowerShell也是不错的选择。

◇针对B/S软件的技能

既然是B/S系统,HTML的一些基本语法要了解,包括:超链接、form的提交等。

B/S的系统,对Web接口的调用几乎是免不了的。因此,要有基本的HTTP协议的常识,包括:Request/Response的区别、GET/POST的区别、知道常见的HTTP状态码。

如果这个B/S系统里面,大量使用JavaScript,那最好稍微了解一下JS的语法;同样的,如果B/S系统中大量使用XML,也需要具备基本的XML知识。

◇针对C/S软件的技能

假如测试的C/S软件大量使用动态库。测试人员最好稍微懂一点C语言的语法,因为大多数动态库的导出函数声明,都是用C语言描述。

假如这个C/S软件经常使用多进程及管道,那还得了解一下标准输入/标准输出/管道的基本概念。

◇数据库相关的技能

无论是B/S还是C/S,可能都会涉及到数据库。这时候,灰盒测试的家伙就需要懂一些数据库相关的知识,包括:基本SQL语法,用上述提到的脚本进行数据库记录的增删改查。

◇网络相关的技能

假如你测试的软件,其内部模块还涉及网络通讯,那最好还要掌握一些基本的网络知识,包括:TCP/UDP的概念、用上述提到的脚本进行简单的SOCKET编程。

★结尾

以上就是开展灰盒测试之前,在管理上要进行的准备工作。本系列的下一个帖子,俺介绍一下具体的技术实现。

模块接口类型概述

★关于实现方式

在前面的帖子里,俺提到过基于脚本的灰盒测试。后面聊具体的技术手段时,会侧重于Python脚本(这正好可以跟俺写的另一个系列“为什么俺推荐Python”遥相呼应)。当然啦,为了照顾那些不用Python的同学,其它的技术手段,俺也会顺带提一下。

关于Python的版本,(截至到目前)有两个系列:2.x版本和3.x版本。这两种版本不但在语法上有一定的差异,而且内置的标准库也有不同。考虑到目前那些使用Python 的开源项目,还是用2.x版本居多,所以俺后续在介绍Python脚本实现时,也会侧重于2.x版本。

★各种接口的分类

由于灰盒测试的技术实现,是一个比较大的话题,涉及面会比较宽。为了保持一定的条理性,避免大伙儿看着看着就迷糊了,俺打算根据模块的接口类型(也就是模块间的交互类型)来叙述。每种类型,单独开一个帖子来具体介绍。

◇根据是否跨进程来分类

如果从进程的角度来看,交互双方的模块可能在同一个进程,也可能在不同的进程。因

此,模块间的交互可以分为“进程内”、“跨进程”两大类(不知进程为何物,请看这里的介绍)。对于进程间的交互,还专门有一个洋文的缩写——IPC。

◇根据是否跨主机来分类

如果从机器的角度看,交互的双方可能在同一个主机,也可能在不同的主机。因此,模块间的交互类型还可以分为“主机内”、“跨主机”两大类。“主机间”的交互,必定也是“跨进程”的。反之则不然。

顺便提一下:如果从耦合的角度来看,跨主机的交互比主机内的交互,耦合低;跨进程的交互比进程间的交互,耦合低。(不知道耦合为何物的同学,请看这里的介绍)

由于不存在“跨主机不跨进程”的接口方式,所以上述两种分类维度排列组合之后,有3种可能。每种俺单独开一个帖子,请看:

接口测试实战——跨主机的交互方式

接口测试实战——主机内的跨进程交互方式

接口测试实战——进程内的交互方式

跨主机的交互方式,必然涉及到网络(为了防止爱抬杠的同学挑刺,事先声明:本节提及的网络,均是基于TCP/IP网络)。在TCP/IP协议栈的4个层次中(参见这里),模块间的交互方式主要是位于上面两层(传输层、应用层)。

有些软件系统,直接采用某种现成的应用层协议(比如HTTP)来进行跨主机的通讯。这时候,测试人员就只需关心该应用层协议,不用操心传输层是如何实现的。

还有一些软件系统,自己实现了某种专有的应用层协议。这种情况下,对测试人员的要求就比较高了——测试人员需要大致了解传输层的知识以及该专有应用协议的格式。(具体请看本帖的Socket这一节)

★基于Web接口的交互(HTTP协议)

由于这几年B/S系统大行其道,而B/S系统,总是离不开HTTP协议,所以俺首先来介绍它。

在B/S系统中,服务端(也叫后端)总是会提供一些Web接口给客户端(前端)进行调用。这种调用总是基于HTTP协议来进行(HTTP协议的介绍,请看维基百科的这里)。当你针对服务端进行灰盒测试,你需要模拟客户端的各种HTTP请求(既要包括合法的请求,也要包括各种非法的、无效的请求),然后再检验服务端返回的响应(Response)内容。如果响应内容不符合接口文档的约定,就表明该服务端模块出Bug了。

HTTP请求(Request),常用的主要是GET方式和POST方式。这两者的用途及区别,维基百科上已有,俺就不浪费口水了,直接说如何进行脚本编程。

◇使用内置的标准模块

在Python脚本中,内置了完善的模块(urllib和urllib2),以便于你操作HTTP协议。对于简单的使用,urllib就足够了。

比如俺想用GET方式抓取Google的主页,只需如下3行代码:

import urllib

f = urllib.urlopen("https://www.wendangku.net/doc/88679716.html,/")

print f.read()

如果想往某个Web接口POST数据,并得到服务端的返回内容,只需再增加1行代码(构造POST参数):

import urllib

params = urllib.urlencode({name1:value1, name2:value2})

f = urllib.urlopen("http://xxxx/xxxx", params)

print f.read()

如果需要一些复杂点的功能(比如:操作cookie、使用带认证的proxy),urllib2就可以派上用场了。更多的使用细节,请看洋文的官方文档(这里和这里)。

◇使用cURL

俺博客的老读者,或许记得俺在09年初写过的一个帖子——cURL(优秀的应用层网络协议库)。看完这个帖子,你就能领会到:cURL是一个非常牛X的网络协议库,支持很多种网络协议(显然也包括HTTP)。这么牛X的一个开源库,自然会有不少编程语言对其进行包裹。下面俺把cURL相关的脚本语言及其开源项目列一个表格。如果你不喜欢用Python,或许可以改用俺列举的其它脚本语言。

语言/平台开源项目

Python pycurl

Ruby Curb

Perl WWW::Curl::Easy

dotNet https://www.wendangku.net/doc/88679716.html,

★基于数据库的交互

在现有软件系统的开发过程中,操作数据库也属于家常便饭。因此,聊完HTTP协议之后,就得来聊一下数据库的操作。眼下,大部分程序员都是远程操作数据库,所以俺把数据库的操作也归入“跨主机”交互方式。(其实本节的内容也适用于操作本机数据库)在很多软件系统中,软件模块需要从数据库中读取数据或者把自己生成的数据存储到数据库中。因此,测试人员需要通过一些测试脚本,在数据库中制造测试数据,以作为软件模块的输入;或者在软件模块把数据保存到数据库之后,验证其输出的数据是否符合接口文档的约定。

◇跨数据库的接口

所谓的“跨数据库的接口”,顾名思义,就是这种编程接口可以支持多种数据库产品。如果你没有其它特殊的要求(比如性能),俺建议尽量用这种方式操作数据库。这样的好处是,万一哪天数据库平台换了,你的测试脚本可以不用大改(甚至不改)。

1、ODBC

ODBC是一种三跨(跨数据库、跨操作系统、跨编程语言)的数据库接口。大部分知名的数据库软件都支持ODBC方式访问。

Python有不止一个的ODBC开源项目,可以考虑用PyODBC或ceODBC。

2、JDBC

对于搞Java开发的同学,应该很熟悉JDBC。不过很多人有一个误解,以为只有Java 才可以进行JDBC编程。其实不然!自从前几年JVM开始效仿DotNet,支持多种编程语言之后,很多脚本语言也可以在JVM上跑起来了。比如Python(JVM上叫Jython)、Ruby(JVM上叫JRuby)、Groovy。作为测试人员,你也可以利用上述脚本语言,编写基于JDBC的数据库测试脚本。

3、ADO / https://www.wendangku.net/doc/88679716.html,

ADO / https://www.wendangku.net/doc/88679716.html,(以下简称ADO)是微软设计的跨数据库编程接口。既然是微软搞得,秉承其一贯风格,自然是不跨操作系统的。如果你所有的测试工作都在Windows平台上,也可以考虑用ADO来访问数据库。

如果要用Python进行ADO编程,可以考虑用PyWin32开源项目(官网在这里)。它是专门针对Windows平台的Python扩展,让Python可以很方便地调用各种Win32的API(包括ADO的API)。

你还可以使用基于dotNet平台之上脚本语言。比如IronPython、IronRuby等。这些运行于DotNet之上的脚本语言,自然也就具有操作ADO的能力。

◇特定数据库的接口

前面已经提到“跨数据库的接口”有种种好处,那啥时候需要用特定数据库的接口捏?有时候,你需要使用某个数据库专有的某个特色功能,这时候,通用的数据库接口可能就搞不定了,你就需要用该数据库特定的编程接口来写脚本。当然,这种情况不是很多见。

下面,俺把几种常见数据库及其对应的Python开源项目列在如下表格中。

数据库 Python开源项目

Oracle cx_Oracle

SQL Server pymssql

DB2pydb2

MySQL MySQL-Python

PostgreSQL psycopg2

SQLite(Python内置)

◇关于Python的补充说明

刚才介绍了多个操作数据库的Python开源项目。俺顺便补充一下:Python社区制定了一个数据库操作的规范。那些比较靠谱的数据库操作的模块,都会遵循该规范。因此,你只要熟悉了某一个模块,也就很容易熟悉其它模块。

★基于网络文件系统的交互(NFS)

网络文件系统存在的目的,就是把跨主机的文件操作,伪装成本机的文件操作。所以,对NFS的灰盒测试,放到后面的帖子(主机内的跨进程交互方式)一起聊。

★基于其它应用层协议的交互

还有另外一些应用层的网络协议,其应用范围没有HTTP协议那么广,因此,Python 没有把它纳入到内置的标准模块中。这时候,前面提到的PycURL就可以派上用场了。你只要安装一个PycURL,就可以搞定十几种应用层协议(FTP,FTPS,Gopher,SCP,SFTP,TFTP,TELNET,LDAP,LDAPS,IMAP,POP3,SMTP),非常

之爽!

★基于Socket的交互

前面提到,如果软件系统自己实现了专有的应用层协议,那测试人员进行灰盒测试时,就必须了解该专有协议的格式以及传输层的知识。在这种情况下,测试人员可能需要直接和Socket打交道。

Python内置了对socket的支持,Python官方的洋文介绍在这里。Python的socket API和传统的伯克利套接字API很像,如果你之前写过C语言的socket程序,那搞定Python的socket程序肯定是不在话下滴。

但你千万别高兴得太早。用脚本来模拟软件模块之间的socket通讯,主要难点往往不在于socket,而在于专有协议本身。有些专有的通讯协议格式多变且复杂,有些虽然格式不太复杂,但是通讯双方交互的逻辑很复杂。因此,在socket层面进行灰盒测试,测试人员要多花精力在这方面。

对“跨主机的模块接口”该如何进行灰盒测试,就介绍到这里。下一个帖子介绍“主机内跨进程的模块接口”该如何搞。

相关文档