六个月前,开始推广BDD。时至,已经有了1200个情景(Scenario)。如果把每个情景,当做一个自动化测试用例,那么短短半年,我们已经从无到有,开发了1200个测试用例。在没有BDD的过去五年中,我们一共才开发了2000个自动化测试用例。粗略地计算下:

  ● 过去2000/5=400个/年

  ● 现在1200/0.5=2400个/年

  即BDD使我们的自动化开发效率,提高了五倍,是原来的六倍。(等我先我自豪一下,hiahia。)

  越多越慢

  慢着!还不能高兴地太早。高效的自动化开发,带来了新的问题。突然一下子多起来的测试用例,让自动化执行时间变长了。每次的nightly build/test的时间,竟然已经接近12小时。如果加上双平台,那么跑上一轮自动化测试,要整整等上才能知道结果。在推广持续集成的现在(推广CI的博客,我会陆续登出),只要有代码提交,便运行的自动化测试,竟要耗上一整天,才能对提交的代码有一个反馈?!这不管对测试人员,还是研发人员,都是不可以接受的。

  自然,简单的解决办法,少跑。从每个Feature(功能)中,精心挑选出基础的Scenario(场景),每次只运行这些基础的场景。这样子,便无法叫做回归测试,顶多算是验收测试,或者冒烟测试。这个做法,大家说的烂大街了,挑呗,没啥难的。

  可我不偏不要烂大街!自动化测试开发的意义,是要多跑!多测!不间断地验证提交代码的正确!回归正确!要真是写了个脚本,一个礼拜跑一次,那也太金贵了!因此,一场轰轰烈烈的为自动化测试提速的运动展开鸟。

  以下按照提速有效性,降序排列,越往后,提速越小。

  提速法1:降低Setup/Cleanup的层次。

  举一个在Eclipse的workspace中创建Java文件的例子。

Scenario: create java fileinws 

02   GivenIhave an Eclipse workspace 

03   WhenIcreate anewjava file with name"Student" 

04   Then eclipse should create a file with name"Student.java"as:

05    """ 

06    publicclassStudent { 

07     public Student() {

08     } 

09    } 

10    """ 
 


  修改前,此处的step:

Given /^Ihave an Eclipse workspace$/do 

2   eclipse.new_workspace() 

3 end
 


  但是,当测试用例变得越来越多时,每个用例都需要"Given an Eclipse workspace",这时候,要思考一下,有没有什么底层的,快速的办法,生成一个空的"workspace"呢?答案是,直接写文件。因此,我们大可以将上述step,改为:

Given /^Ihave an Eclipse workspace$/do 

  system("cp -r #{$empty_ws} .")

end
 


  以此类推,需要“delete_user”的地方,大可以直接delete database,甚至可以使用数据库镜像与回滚(db snapshot/rotate)的工具。理由:我要测试的步骤是“create a new java file”,而前后的步骤,只是我所需要的环境。搭箭环境的步骤,以快,准,稳为原则,尽量避免免调用系统接口浪费资源与时间。

  提速法2:提高Setup/Cleanup的层次。

  在降低了部分Setup/Cleanup的层次后,我们会发现,有些Setup/Cleanup,是不需要每一个Scenario都要运行的。如远程Login的链接,如登录Web页面的链接等等。hook.rb中,可能表现为:

Beforedo 

2   @cli= Cli.login(host, user, password) 

3   @web= Web.login(url, user, password) 

4 end 

5 Afterdo 

6   @cli.logout 

7   @web.logout 

8 end
 


  这些链接是属于无状态的,并不会因为这次提交了某个cmd,或者http request而影响链接本身。为了避免重复登录、退出,可以在一开始(所有Scenario开始前)登录,而在结束后(所有Scenario结束后)退出。改写后的hook.rb为:

@cli= Cli.login 

2 @web= Web.login 

3   

4 at_exitdo 

5   @cli.logout 

6   @web.logout 

7 end
 


  这样,避免了每次登录、退出所需要的时间