我希望本文有助于你了解测试软件是一件很重要也是一件不简单的事。

  我们有一个程序,叫 ShuffleArray (),是用来洗牌的,我见过N多千变万化的 ShuffleArray (),但是似乎从来没有要想过怎么去测试之。所以,我在面试中我经常会问如何测试 ShuffleArray (),没想到这个问题居然难倒了很多有多年编程经验的人。对于这类的问题,其实,测试程序可能比算法更难写,代码更多。而这个问题正好可以加强一下我在《我们需要专职的 QA 吗?》中我所推崇的——开发人员更适合做测试的观点。

  我们先来看几个算法(第一个比较诡异高深,第二个比较偷机取巧,第三个比较通俗易懂)

  递归二分方法

  有一次是有一个朋友做了一个网页版的扑克游戏,他用到的算法比较诡异,是用递归+二分法,我说这个程序恐怕不对吧。他觉得挺对的,说测试了没有问题。他的程序大致如下(原来的是用 Javascript 写的,我在这里凭记忆用C复现一下):

//递归二分方法
constsize_t MAXLEN =10;
constcharTestArr[MAXLEN] = {'A','B','C','D','E','F','G','H','I','J'};

staticcharRecurArr[MAXLEN]={0};
staticintcnt =0;
voidShuffleArray_Recursive_Tmp (char* arr,intlen)
{
if(cnt > MAXLEN || len <=0){
return;
}

intpos = rand () % len;
RecurArr[cnt++] = arr[pos];
if(len==1)return;
ShuffleArray_Recursive_Tmp (arr, pos);
ShuffleArray_Recursive_Tmp (arr+pos+1, len-pos-1);
}

voidShuffleArray_Recursive (char* arr,intlen)
{
memset (RecurArr,0,sizeof(RecurArr));
cnt=0;
ShuffleArray_Recursive_Tmp (arr, len);
memcpy (arr, RecurArr, len);
}

voidmain ()
{
chartemp[MAXLEN]={0};
for(inti=0; i    {
strncpy (temp, TestArr, MAXLEN);
ShuffleArray_Recursive ((char*) temp, MAXLEN);
}
}

  随便测试几次,还真像那么回事:

第一次:D C A B H E G F I J
第二次:C A B D H G E F J I
第三次:A B H F C E D G I J
第四次:B A H G E C D F J I
第五次:F B A D C E H G I J

  快排 Hack 法

  让我们再看一个 hack 快排的洗牌程序(只看算法,省去别的代码):

intcompare (constvoid*a,constvoid*b )
{
returnrand ()%3-1;
}

voidShuffleArray_Sort (char* arr,intlen)
{
qsort ( (void*) arr, (size_t) len,sizeof(char), compare );
}

  运行个几次,感觉得还像那么回事:

第一次:H C D J F E A G B I
第二次:B F J D C E I H G A
第三次:C G D E J F B I A H
第四次:H C B J D F G E I A
第五次:D B C F E A I H G J

  看不出有什么破绽。