【工作经历:阿里巴巴搜索技术研发中心QA ,百度新产品测试部QA】 【领域:测试分析,自动化测试,性能测试,安全测试 】 【个人定位:高级测试工程师+培训师+领域产品专家】

基于调试的测试技术

上一篇 / 下一篇  2012-01-16 02:12:53 / 个人分类:白盒测试

很久没有发技术文章了,实在对不住大家。今天决定放点技术的东西出来跟大家交流下。

基于调试的测试技术

大家都知道,通过gdb可以动态的跟踪程序,通过gdb,你可以实时的追踪任何你想了解,甚至是介入的逻辑,实现对程序的完全控制。那么测试和调试技术结合,会带来什么那。这是个很有意思的中间地带。

趁在这边重新接触了c++的测试,就做了一些探索。

一个程序,其实是可以看成一个树结构,树有一个树根入口,然后不同的数据,通向不同的业务逻辑和执行路径。
但是程序中,除了简单的if else之外,还有一些for while之类的循环,这些会导致程序的代码运行不再是简单从上到下,而是充满了各种的”短路“,“调头”等。

一个只有if else switch的程序,是一个树结构。
一个带有for等循环语句的程序,是一个复杂的图结构。

如果你输入一些数据给程序,程序就会分拆,分析数据,然后根据具体的数据,去走各种各样的逻辑。
这根测试用例是一样的,你如果测试一个程序,那么这个程序有多少种测试数据,其实就代表了,程序有多少种的业务规则。


简单的以百度搜索为例,当你输入不同的词语,所出现的内容是不一样的。这就是程序的逻辑不同。
比如,你输入abc,他们会出abc
你输入1+2,他就会弹出框架算应用。
如果你输入一个不存在的词,他会提示你找不到等等。

这些不同,是由底层的代码逻辑,和一些附属数据决定的。其实就是数据结构和算法决定了一切。
那么对于一个已经设计好的程序,一旦他的代码和数据确定,那么他的行为就确定了。
它自身会有多少个逻辑分支,会有多少的异常,都已经确定了。

而QA回去度量这个程序是否满足需求,功能是否OK,代码质量如何,测试覆盖率有多少等等。
其实包括需求在内的范围,是程序所不能控制的。需要QA严格保证。

但是对于已经确定的代码,却包含了所有的分支逻辑。也就是它不能保证它正确,但是它能知道自己到底做了哪些事情。一个程序所表示的所有逻辑中,就有一部分是为了保证需求的。

那么对于QA感兴趣的,就有如下几点。

1、找到所有的分支逻辑,并测试它。确保行为可预期。并消除一些bug。
2、找到包含业务逻辑的分支逻辑,针对性的验证,消除需求和功能上的bug

对于第一点,我目前还没有去研究,因为它需要专家才可以搞定,需要你了解汇编,编译原理和语法分析等。代价很大。
而对于第二天,却有个小技巧可以做。

对于一般的项目而言,如果一个项目是升级项目,或者这个项目已经有了应用的场景,可以构造,甚至是拿到具体的应用数据。那么容易到了。
举个例子,就好比,如果是搜索引擎升级,那么我可以拿到所有的日志,或者用户的query,然后测试引擎。

通过ccover,或者gcov,c++的程序是可以统计到测试覆盖率的,可以定位到具体的代码行。然后补充自己的测试用例。通过这些测试覆盖率工具,我们可以把测试做的足够透明,并能保证覆盖率和测试用例的完备。
但是对于测试数据的生成,却需要QA自己去构造实现。这是QA里面很耗时的一个工作流程。

那么就诞生了一个新的想法,能不能从线上的数据,反推出测试用例数据。或者根据批量的数据,然后找出有效的测试用例。

gdb可以很好的跟踪到程序的每一个细节,如果有一份批量的数据被灌入了某个程序,这个程序的所有的运行轨迹,都可以被探测到,只需要从里面拆解出所有的分支,并得到数据,那么就可以很好的实现这个过程了。


所以我找了一个项目做测试,自己也编写了一个程序demo,然后使用gdb去跟踪整个过程。
我使用了break+commmands命令,保持gdb非交互运行,
使用脚本自动对程序中所有的分支,循环自动下断点。

因为这些分支代表了业务逻辑,而for循环则代表了一些新分支的诞生。都是需要跟踪的。

然后记录所有的断点情况,如下是一个断点情况。

1 2 3 4 5 5 5 5 6 7 5 5 8 5 9 5 10 11 12
1 2 3 4 是依次执行的条件分支
5在循环体内,以下是若干分支
5 6 7   
5 8  
5 9 
5 10 11 12

如此,可以看出,一个程序的执行,其实是一个序列,这个序列包含了分支和循环,所以导致了有些断点总是为被不断的执行,直到所有的数据遍历完才退出。



为了方便的分析,对数据做处理,生成一个树结构。

Main是树的开头
If开始是一个必经的节点,if之后的语句,会分支执行,看成分支点
For循环会导致断点重复,所以把for开始处看成分支点,每个for执行看成一个子树。
函数调用也会导致重复,让它不重复,如果调用栈发生了变化,就认为是新增子节点
经过上面的步骤,所有的叶子节点就可以代表程序的轨迹了


然后重新对数据做处理,就出现了如下的结构
这个结构非常好的代表了程序的逻辑。


它从根节点开始,然后不断的经过各种分支,到达第一个叶子节点后,重新又从某个for循环处衍生出新的分支。


从测试角度考虑,只要能够遍历所有的叶子节点,那么就可以确保测试覆盖率达到一个非常理想的境界。

如果不同的数据,但是业务处理逻辑一样,那么这些数据都走过了同样的节点序列,那么就认为这些数据是重复的测试用例,只需要选取一个就可以了。

通过gdb的运行log和这些树结构,就可以非常清楚的知道程序的算法逻辑,找到没有被覆盖的分支,并能消除重复的测试用例。


深入的分析gdb的log,可以挖掘更多的有价值的东西。
比如测试覆盖率,通过gdb就可以很好的度量覆盖率


以下是可以通过gdb做到的。

测试覆盖逻辑路径图(ccover,lcov)
代码覆盖率统计(ccover,gcov)
从批量数据中挖掘测试用例
断点切入测试
性能分析(结合google-perftools)
Fuzz测试
代码分析
抛砖引玉。。。。


把调试技术应用于测试会带来很多惊喜


目前我做了一些进一步的探索。
1、如果反向从gdb运行log推理出测试数据。(探索中)
2、自动找到未被遍历的条件,协助分析。(已完成)
3、自动设置断点状态去走向未被执行的逻辑,比如把true改变为false。(价值不大,可以探测出问题,但是会影响业务逻辑)


以某个项目为例
运行gdbtest -run "bin/qs qs.data"
然后得出的一个报表,就可以看到那些逻辑被执行了,那些逻辑没有执行。然后做一些对应的测试用例添加就可以了。





TAG:

yuanspring的个人空间 引用 删除 yuanspring   /   2012-01-17 13:56:28
猎头职位:岗位名称:自动化高级测试工程师(特别说明:如果您是某公司的自动化测试高级工程师,如果您是测试架构师,如果您想要从研发转到测试,如果您期待挑战技术、如果您喜欢跟一帮聪明、优秀的工程师工作,如果您不爱加班,看以下的这个职位吧,如果您不想承担北、上高额的房价,不想在漂泊、期待工作和生活的完美结合。看这个职位吧。更多的情况请联络相应猎头顾问QQ:30683890 )

自动化测试高级工程师(以下职位JD仅供参考,具体请与猎头顾问联络,她会为你介绍这个职位的详细情况。这个职位期待那些了解数据库、有研发背景,语言不限、懂脚本语言、具白盒测试经历、具自动化测试经历的测试工程师)
 

评分:0

我来说两句

Open Toolbar