论坛首页 综合技术论坛

测试写到什么程度算足够?

浏览 18399 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-11-19  
100%的测试覆盖率
这是一个很显而易见的答案。但是我不认为这是正确的答案。下面是一个小例子:
private int[] map = new int[] {
  1, 3, 5, 8};
public int oddNumber(int index) {
  return map[index - 1];
}

写一个简单的测试
@Test
public void first_odd_number_should_be_one() {
  assertEquals(1, oddNumber(1));
}

这个测试是不是覆盖了100%的代码呢?我认为是覆盖了的。但是是不是真的测试了所有的执行路径呢?显然没有。oddNumber(4)应该是7,但是这个程序会返回8。我们改一个写法:
public int oddNumber(int index) {
  switch(index) {
    case 1: return 1;
    case 2:return 3;
    case 3: return 5;
    case 4: return 8;
  }
  throw new UnsupportedOperationException();
}

换了一种写法之后,测试覆盖率立马就下去了。差别就在于,在第二种写法把执行路径对应到了字面的静态路径上了。所以说,测试应该覆盖是否完全的标准,应该是以动态路径为准,而不是以静态路径为准。同时,也提醒我们,想要靠最后根据测试覆盖率来补测试,是不能让你做到TDD时同等程度的自信的。
在TWU上学的时候,老师给了一个简单的准则:
代码增一行太多,减一行太少
当然,老师是用英文教课的,我是把意思用中文翻译了一下。这句话是说,代码不能多不能少,以恰好让所有测试通过为最佳。为了验证这个道理,据老师说,ThoughtWorks UK有一个开发人员写了一个工具用来“删代码”。如果有一行代码是能够删掉之后还能让所有测试都通过的,那么就删掉它。我觉得,这个准则很有务实,也很有用。同时,也回答了另外一个问题,是不是要给所有的类写对应的测试类来覆盖其所有的行为?我认为没有根据这个准则,答案应该是没有必要。只要你的测试覆盖了这个类的所有执行路径就可以了。至于这个测试是不是针对这个类独立进行测试的,是单元测试还是功能测试,是黑盒测试还是白盒测试,都不重要。重要的是,你删掉这个类中一行或者几行,都会让所有测试中至少一个测试失败。这就能说明,你的测试是写到位了。
当然,再加一些怀疑和批评的态度。对于上面那个放之四海皆准的准则,有一个例外:那就是这个准则只关心程序的正确性,但是我要说程序的行为是由正确性和效率共同组成的。举一个空泛的例子:
if (a) {
 doSomethingUnderConditionA();
} else if (b) {
 doSomethingUnderConditionB();
}

条件A和B可能在匹配的集合上是包含关系,也就是说一个是另外一个的强条件。假设A是更强的条件,那么在条件更强的情况下,我们往往可以给一个更有效率的解。但是有可能,如果没有条件A这个分支,所有情况都走条件B的分支,解仍然是正确的。所有说,A的存在不影响程序的正确性,只影响了程序在特定条件下的效率。那么,在这种情况下,就不能说代码增一行太多了。
   发表时间:2006-11-20  
引用

,ThoughtWorks UK有一个开发人员写了一个工具用来“删代码”。


那么在写代码后再删代码?
那么测试的作用就比代码要重要的多了
PS:为什么精华的帖子没什么人看呢?
0 请登录后投票
   发表时间:2006-11-20  
所以TDD中Test First是前提。任何后补上的Test都很难驱动简单设计,也就不能随意“删代码”。

有人说TDD和Pair Programming是XP的两个最难的门槛,所以初学者可以先绕行。但问题是没有这两者,根本就不是XP。
0 请登录后投票
   发表时间:2006-11-20  
代码增一行太多,减一行太少是很难。
因为那样要写一个正确、健壮、有效的测试,这太难了。不是说不要对你的测试进行测试么?
这样,对于自动删程序判断是否还可以通过测试这种方式来说,没有自动化的测试保证是不可以的。但是如果是手动,凭人脑……那么就……

所以,是不是说测试应该保证主干正确性,或者像Rod说的那样代码覆盖率不能说明一切。对于稀的测试path,应该尽量凭经验,没法强求吧。
0 请登录后投票
   发表时间:2006-11-20  
抛出异常的爱 写道
引用

,ThoughtWorks UK有一个开发人员写了一个工具用来“删代码”。


那么在写代码后再删代码?
那么测试的作用就比代码要重要的多了
PS:为什么精华的帖子没什么人看呢?

据我猜想这个工具应该是一个玩笑。举这个例子的目的是说,只要你的测试没有覆盖到你写的某一块代码,这一块代码任何人都有权利删除。
0 请登录后投票
   发表时间:2006-11-20  
Tin 写道
代码增一行太多,减一行太少是很难。
因为那样要写一个正确、健壮、有效的测试,这太难了。不是说不要对你的测试进行测试么?
这样,对于自动删程序判断是否还可以通过测试这种方式来说,没有自动化的测试保证是不可以的。但是如果是手动,凭人脑……那么就……

所以,是不是说测试应该保证主干正确性,或者像Rod说的那样代码覆盖率不能说明一切。对于稀的测试path,应该尽量凭经验,没法强求吧。

测试的正确性之所以不用另外一个测试来保证,是因为测试自身没有复杂的逻辑,其正确性就是靠你的人脑。测试不正确,不是测试代码的不正确,而是你的想法错了。
很少运行到的路径是不是要测试就看自己的权衡了。在时间和质量之间的权衡。这种权衡当然也是要符合敏捷的原则的,就是总是选择诸多选择中投入最少,收益最高的那个。
0 请登录后投票
   发表时间:2006-11-20  
说实话,没有TDD也可以XP。但是XP做惯了的人,一定会在可能的情况下,尽量选择TDD的开发方式。曾经有人告诉我一位前辈在没法写测试的情况下是如何写代码的。他会把所有的任务给一个个的列出来,相当于写一个不可运行的测试,然后一个个的打钩,做起来一样有条不紊的。
结对编程也是一样的。我也不认为不结对就不可以做XP了。如果任务真的很简单,干嘛要放两个人在同一件的事情上?
0 请登录后投票
   发表时间:2006-11-20  
Tin 写道
代码增一行太多,减一行太少是很难。
因为那样要写一个正确、健壮、有效的测试,这太难了。不是说不要对你的测试进行测试么?
这样,对于自动删程序判断是否还可以通过测试这种方式来说,没有自动化的测试保证是不可以的。但是如果是手动,凭人脑……那么就……

所以,是不是说测试应该保证主干正确性,或者像Rod说的那样代码覆盖率不能说明一切。对于稀的测试path,应该尽量凭经验,没法强求吧。


“没有自动化的测试保证是不可以的”,所以所有测试都要自动化啊!

测试难写,正是因为现实问题的复杂。而解决现实问题正是发挥我们聪明才智的时候。

测试难写,还强迫我们写出易于测试的程序,你要先问一下自己,是这个问题难测试,还是你的代码难以测试。

写测试是很难,幸运的是,程序员是聪明的,而重复的手动测试却不是聪明人愿意做的。
0 请登录后投票
   发表时间:2006-11-20  
taowen 写道
说实话,没有TDD也可以XP。但是XP做惯了的人,一定会在可能的情况下,尽量选择TDD的开发方式。曾经有人告诉我一位前辈在没法写测试的情况下是如何写代码的。他会把所有的任务给一个个的列出来,相当于写一个不可运行的测试,然后一个个的打钩,做起来一样有条不紊的。
结对编程也是一样的。我也不认为不结对就不可以做XP了。如果任务真的很简单,干嘛要放两个人在同一件的事情上?


有道理。

我的意思是,没有TDD和结对,是让人觉得很不舒服的XP,效率会大打折扣,只能说是一种妥协的XP。

也许我的观点过于理想化了,但是我还是想追求最高效率的开发过程。
0 请登录后投票
   发表时间:2006-11-20  
taowen 写道
说实话,没有TDD也可以XP。
如果任务真的很简单,干嘛要放两个人在同一件的事情上?

嗯,说得好呀。这是自我解放,做事可以Pragmatic,从心。制度应该给不动脑子的人。

测试的入手点的确是需要动脑子保证的,同样的场景可能有很多种测试的思路,所以如你所说这应该是由写测试的人决定,而不能通过另外一个测试保证。TDD让你从开始考虑验收的检查点,从一开始就在让思路清晰。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics