探索式测试是一种软件测试手段,不是一种具体的软件测试技术(如等价类划分、边界值分析、组合测试等),它需要测试人员同时开展测试学习、测试设计、测试执行和测试结果评估等活动,以持续优化测试工作。怎么样在日常的测试流程中实施探索式测试,同时不与公司的现有研发流程产生冲突呢?SMART原则为探索式测试提供了很好的建议。51Testing软件测试网}v
G;K[@4] ● Specific(具体的):测试需要一个具体的目标。51Testing软件测试网m3N'L3OZ zM/]q
51Testing软件测试网nYc&Q+{8F]"d4m af ● Measurable(可度量的):有明确的度量可以评估目标是否达成。51Testing软件测试网V$Hx:K/q
G`cH2}0 ● Achievable(可实现的):当前的目标应该是可实现的。这潜在地要求将一个大的目标分解为多个小目标,每个小目标也是具体的、可度量的。此外,跟踪小目标的完成情况也提供了整体进度的可度量性。
9L-D:Zi@-Mx?f [0
f%_7Ru){0 ● Relevant(相关的):目标要切合当前语境,符合团队利益,且不忘企业愿景(vision)。
|1u\
~!|0
Ua5z9H'X
AH4g0 ● Time-boxed(有时间限制的):为每个目标设定一个合理的最后期限。这是帮助测试人员在固定的时间窗口(time window)中排除不相关干扰、专注工作51Testing软件测试网b']*X&o#T[W
51Testing软件测试网&o5PFD+^bQe%\ 下面引入几个代表性Backend ServerBug的发现过程来解释一下探索式测试的理论,以及如何在我们的日常测试中加入这个测试手段,提高发现bug 的效率。
8O8j3|.{,a#J;k A^-yrr0'V_sd
V9cnt1?
_0 【场景1】输入参数探索式测试Bug:非法的用户Id 发送到了备份的数据中心导致了服务器出现宕机51Testing软件测试网6xmY$@XH5h
51Testing软件测试网nmxF(|k8G1g)R(y7aU
通过日常Review 服务器端软件Bug列表,QA测试发现输入参数导致服务器出现异常行为的Bug
,引入对同类型问题的思考,输入参数会导致Server 提供的API产生异常,那么其他应用类型的Server会有这种类似问题?Server
内部是怎么样的一个处理逻辑才会导致crush?
.z
dJa-B0 w@9m.@B[D#n N
C0 那么先从自己负责的Server下手,通过静态扫描Code 发现“可疑code”51Testing软件测试网pP6us(T0hAW
CmResult CMs****Gsb****RequestPdu::解码(CCmMessageBlock &aData) M fp5PXe0{51Testing软件测试网u1rL X
N%DB8i ...........51Testing软件测试网/?!`{ e
VI(L
y+q size_t nPos = strKey.find('^');//可疑code ._6F Fu?l%a0if (nPos != string::npos) Dd:qO3Jz7O.SF0{ -l+\(O"w2K:LA0strKey.resize(nPos); #|Hjq&yE*Y k0}51Testing软件测试网5?yT"L/~Uu m_user.用户ID = strKey;51Testing软件测试网2cBz[y` .......51Testing软件测试网"D&MZ5[4}E2h8B"~.vQ return CM_OK; ?:R8h-tf#y8Rla*g$W#y022} |
51Testing软件测试网o%O-UC
~$hC5Nq%~X4L
看来DEV
下一个逻辑用到了Decode代码解析出来的m_user.用户ID,但是这个值却是依赖于特殊字符’^’作为分隔符,看来我们测试的重点就是让解析的值
出错,那么肯定会造成程序的出错,到底会出什么错呢?拭目以待了!接下来为了测试出这个logical ,需要design
Case走进这个分支的代码,通过背景知识了解,这个解码的方法输入参数CCmMessageBlock
&aData,是通过Primary数据中心发到另一个数据中心(GSB)。Case就可以写出来了,重点是在Primary数据中心构造一
个**Id 带有多个’^’InputValue. 测试结果看到了这个Bug 大家应该知道了,通过探索式的测试方法构造输入参数
,针对性的找到了这个隐藏的Bug,显然这种针对性的构造输入参数,比模糊式的测试发现的bug 效率会有一定提高。
p+n;x[%kC:z
W(};T0*w;uu!bj-vh0 接下来我们来看一下开发如何Fix这个问题的,51Testing软件测试网#x!KjR y:U.B
CmResult CMs****Gsb****RequestPdu::解码(CCmMessageBlock &aData)51Testing软件测试网rj9wmEk
tj {51Testing软件测试网:@!\{x1y"U0N }"\ .............. C'T:Ax ?:N8y0CmResult rv = CMs****Util::GetFromUniqueKey(strUniqueKey, strKey, strSubKey);//Fix code51Testing软件测试网X~Y4Iu)hd%iSS m_user.用户ID = strKey;51Testing软件测试网pu7|_@r8o"ke%D ......... Q#~)ViYw0} |
2@ C1{y{0O"`(U2l0
UniqueKey code logic简单在这里说明一下: not use the specail char to generate the
Key use the each selfkey and selfKey length
作为一个单元;显然这种编程风格非常的规范,特别是针对Server,这样企图通过输入参数破坏程序逻辑就变得很困难了。
j2km hpha U"RHZ0
h;R;w,h1Xjm0 最后,通过对这个bug的学习,采用探索式的思想,需要对Server另外4个APP(App1,App2,App3,App4) 进行统一的静态扫描code;发现App2 存在Null Key issues ,这里就不再累述了。
'LuG5NJj:ZJ)z0【场景2】线程安全性探索式测试Bug Run Two MultiThreadTool with two ****.so 1000 thread cause crush8{ E'M`Gy3}4|0 首先熟悉线程安全性的概念:当对一个复杂对象进行某种操作时,从操作开始到操作结束,被操作的对象往往会经历若干非法的中间状态。调用一个函数
(假设该函数是正确的)操作某对象常常会使该对象暂时陷入不可用的状态(通常称为不稳定状态),等到操作完全结束,该对象才会重新回到完全可用的状态。如
果其他线程企图访问一个处于不可用状态的对象,该对象将不能正确响应从而产生无法预料的结果。51Testing软件测试网!Y:U(r`G
j8Gqj ~0 那么QA怎么测试一个程序是否具备了线程的安全性呢?需要通过reviewcode?
显然这是一件很困难的事情,而且效率不一定会高。因为个人感觉多线程的编程本来就比一般的编程要难很多,需要注意的细节多很多。既然不能用白盒测试发现问
题,那么怎么去测试呢?黑盒?
fu:q"|3B
}[S051Testing软件测试网 [\:BHLw5oOl 下面是我在多线程测试中的一些探索,结合这个bug的发现过程和大家分享一下。****.so 一个C++ NativeClient
,提供给Nginix **** Process 使用,考虑到这个NativeClient
可以启动多个连接,多个实例,那么对于测试者来说直接把这个 NativeClient
想象成一个黑色的盒子,测试预期是肯定这个“黑盒子“支持多线程。通过在这个NativeClient加上一层多线程的应用场景,通过多线程模式测试“黑
盒子”的内部的线程安全性,看是否和QA预期结果一致。测试方案确定,用多线程测试多线程,这就需要QA写的多线程自身要具备线程安全性,才能正确达到测
试的预期结果。51Testing软件测试网Z"T
^ F.n
51Testing软件测试网!t^7UA4AJ$zN6Z*j 以下是我当时为了测试开发****..so写的一个C++ 多线程的测试程序。下面摘录控制线程的几个主要方法,相信大家都不会陌生。(线程实体就不在这里摘录了)
6a"q
v'ov
{q!i~/i051Testing软件测试网0W[eZ`51Testing软件测试网,q _4_[6Do
#include "pthread.h"51Testing软件测试网
pnD2Xl|(U#yb)o
E class Mutex +i{9} v2V3B8`z]0{ rn~*U!y1c0public:51Testing软件测试网NW&O3N5?o static void pthreadMutexInit(pthread_mutex_t* aMutex_t); zt9l#Bf5w0static void pthreadCondInit(pthread_cond_t * aCond_t); jE,r`H$^G_v0static void pthreadCondWait(pthread_mutex_t * aMutex_t,pthread_cond_t * aCond_t);
|6c
v,ql&}&B&@"T0static void pthreadCondSignal(pthread_mutex_t * aMutex_t,pthread_cond_t * aCond_t);51Testing软件测试网+u2EO"FMw"G};s static void pthreadCondBroadcast(pthread_cond_t * aCond_t);51Testing软件测试网YY5@ uB5I+y\ } |
3r%M)x%_ px'd'[w)?"\3[0 写好测试程序和makefile 文件,在linux 平台编译成了MultThreadTool 进行测试,通过测试发现上述bug,
通过和Dev Review Code 发现由于回调线程与发送线程(网络线程)在request timeout Condition
重复多次调用了removeClinetTransaction 对象导致了crush。
1jVITIV051Testing软件测试网 wK4xUj!e1?IQ9] 接下来看一下开发解决方案 , 把计划定时器, 取消定时器, onTimeout 放到发送线程,instead of
回调线程.。这样做的好处简化回调线程要处理的逻辑,让网络线程处理这些异常的条件,比如刚刚由于TimeOut 导致的
crush问题。通过这种测试方法,测试线程安全会更高效,在提高QA
测试技术的同时,也最大程度的提高发现这种线程安全性的肯能性。刚刚讲的只是由于线程安全的一个方面,用同样的方法实际上还测试了线程安全性典型的另一个
bug,线程间抢占资源导致的死锁。Bug: A add B as Friend then UpdateB Del A same time
Cause Thread Lock together51Testing软件测试网:yRe7vc
Z:p7_9dSH0 这是个人探索式测试的第一次亲密接触,结合正开展的项目把理论变成了实践。最后总结一下
“探索式测试是一种软件测试手段,不是一种具体的软件测试技术,但是它需要多种测试技术手段的支持”希望这篇文章能帮助QA提高日常的工作效率,同时帮助
DEV 减少同类型错误的二次发生。
GO"Vl8N1i0y0