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

发布新日志

  • 基于调试的测试技术——从批量数据反推测试用例

    2012-01-18 15:46:19

    接上文

    以某个c++项目为例,程序a需要一个输入文件,每行代表一条记录,每行中包含2个字段,一个是qid,一个是title。
    它接受批量的输入数据,然后分析输入做一些算法上的处理,比如数据挖掘,个性化推荐等。

    先进行基本的测试设计,根据需求和细节设计做一些测试用例覆盖。确保需求覆盖率。

    然后构造测试数据,测试数据构造基于历史数据,取线上真实的数据,然后做一些扩展。从三个维度去挑选测试用例数据
    1、线上真实的基本数据,然后做扩展
    2、阅读代码,根据代码逻辑,进行code review,然后做扩展
    3、使用批量数据反推

    依赖上面的两个步骤,就足以保证你的测试覆盖率了。
    这次主要介绍第三种方法。这是一种新维度。

    使用上文的方法,首先做出一个工具,我命名为gdbtest。它自动下断点,然后运行特定的命令,最后分析log。统计数据。然后开始执行如下步骤

    1、分拆你的数据。为了区别不同的测试用例,你必须对输入数据拆分。我取线上1000条记录,然后拆分为1000个文件。当然,线上一般都是百万级以上的数据。具体如何拆分,自己把握吧。采用二分法什么的都可以。

    2、分别使用gdbtest运行你的项目。可以采用多进程加速

    3、最后对所有的log分析,并归类。就可以发现不同的测试用例了。

    4、即使log中断点的信息不同,但是仍然表示测试用例是一样的,可以进一步去重



    我的项目为例,第三步就可以发现200条数据中,有6条记录是走同样逻辑的。
    走同样逻辑的数据的md5值是一样的。
    研究后发现,走不同逻辑的原因是因为有些数据的长度不同,由此可以印证,长度不同的title,也是不同的测试用例。


    然后排除掉长度不同导致的逻辑不同,就可以发现。在所有两百多条记录中,只有三种情况。
    也就是说,其中至少包含了3个最有效的测试用例。
    然后自己分析具体的测试数据就可以了。



    如果你的数据量更大,覆盖度更大,那么发现的测试用例也会更多。

    此方法还有一个好处就是可以用来寻找bad case,这在一些搜索引擎和算法的测试中,是经常用到的。








  • 基于调试的测试技术

    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"
    然后得出的一个报表,就可以看到那些逻辑被执行了,那些逻辑没有执行。然后做一些对应的测试用例添加就可以了。




  • 开始转向Groovy与JRuby

    2010-04-17 17:51:15

    买了两本书。关于这方面的。

    使用ruby的过程中,发现ruby的类库太少了。很多功能用起来不爽,又没有精力去重写。很多地方需要依赖其他的三方库。公司里面的java开发需要一定的java方面的人,目前部门里面的人这方面有建树的人太少了。
    已经形成了一个技术瓶颈。
    自己已经从算法测试中脱离出来了。这方面的知识就不要想了。也没有精力去投入了。慢慢就被边缘化了。
    我要专注在自己的领域里了。


    1、测试技术方案提供。
    2、后台测试自动化设计与实现。
    3、评审后端设计,提供设计意见,测试范围评估。
    4、接口测试。
    5、性能测试

    c++方面,因为岗位关系,已经无法深入了。java还是大有可为的,开始计划转到java方面去研究。

    这方面的后续的计划

    1、java学习
    2、Groovy与JRuby调用java研究。
    3、使用Groovy或者JRuby进行Java方面的接口测试,单元测试。
    4、java代码级别的性能检测
    4、java代码级别的静态检测。







Open Toolbar