单元测试普及(三):测试与你的代码

上一篇 / 下一篇  2012-10-09 08:59:59 / 个人分类:单元测试

HD up%vV0  如果你没有阅读过前一篇文章,请移步

9Hc6u7m7_$X0

K9g+s4{:[ h!~L [8`0  ●单元测试普及(一):以前的测试方式

oe#Nu{+l2`h6h0

3g.Nj x2~?J*ty0  ●单元测试普及(二):更高效地检查bug

t{@Lo F0

)H a%m~ Jh7Y)k0  自动化!51Testing软件测试网+QV|Qy#Ebs

51Testing软件测试网 l)KSn2]^

  通过使用单元测试来代替log,我们已经可以确保测试的可复用性和自我检查能力。不过我们依然做了很多体力活,这也意味着还有提升的余地。运行一个包含测试的HTML文件很容易,但是你需要注意的是,现在的web开发者不可能一整天都在一个浏览器中做测试。所以你可能会需要在3个以上平台上测试5个以上的浏览器,而且浏览器本身可能还需要测试2个版本以上。此时,运行一个HTML就不那么容易了。51Testing软件测试网7hhJQr.o)k"?/E

'N6J~*Y1doO W |2_0  前面所写的测试用例对象是针对JsTestDrive的,JsTestDrive是一个来自谷歌的JavaScript测试框架和测试运行工具。它最大的特点就是运行测试的方式。JsTestDrive运行了一个服务器来完成不同浏览器中的运行工作。理解JsTestDrive工作的最好方式就是实践一下。

%M$h0PYfn4l,h051Testing软件测试网'^ `N,b3v@d6e

   假设jQuery插件位于地址src/difference_in_words.jquery.js,测试用例位于test /difference_in_words_test.js。为了运行这个测试,我们在项目根目录下添加了配置文件jsTestDriver.conf。 测试文件的内容如下:51Testing软件测试网e1P{;@7\e8X?

server: http://localhost:422451Testing软件测试网 ]wy)y5B6j7Z
load:51Testing软件测试网| \u'\G9U"X#D
 - src/*.js
1SW2](]f-oT0 - test/*.js
51Testing软件测试网yFIHk*|'H

  你可以下载最新的JsTestDriver jar 文件。运行这个文件需要事先准备好Java环境。然后在shell中输入下面的命令:

R2V5A$UG0
java -jar JsTestDriver-1.2.2.jar --port 4224

!r-IHCn^`[0   你已经在你的机器中启动了一个JsTestDriver服务端。下一步就是让浏览器访问http://localhost:4224/capture, 它会将浏览器转到一个可用的测试用例并运行。你可以在所有可用的浏览器上运行一遍。然后打开一个新的shell,进入项目目录并输入:

#vVb.zf~hvN-K0
java -jar JsTestDriver-1.2.2.jar --tests all
51Testing软件测试网'c ]Fed `)D7h%Em"X

  过一会你就会看到一些输出,说明测试已经运行,并展示测试是否通过。恭喜,你已经成功地在多个浏览器中进行自动化测试。如果你的机器是在网络中的其他设备,你也可以使用这个服务端进行其他平台的测试(OS X,WindowsLinux),你的iphone,Andriod或者其他设备。你也可以用简单的shell命令对其进行区分。这太令人激动了!

)?U/D4eA6{051Testing软件测试网 Dx[S0fM snH

  JsTestDriver 不仅仅是自动化测试的选择。如果你不喜欢他的assertion框架,它也可以使用QUnit,YUITest和Jasmine进行测试。此外,Yahoo还有YETI,一个类似的工具,特别为YUI测试定制。Zakas最近也发布了YUI Test Standalone,包括了一些类似的基于SeleniumWeb Driver的测试运行器。

.O[2m5THD6I#Ug051Testing软件测试网2A/?-g,`c

  可测试性:使用测试来优化你的代码51Testing软件测试网^L'hMn]Rf)H"d

'j&w/kF6L(i Z:`0  现在,你应该开始意识到单元测试带来的省时,特别是对于JavaScript这种可能运行在多个环境下的语言。单元测试相对其他log的方式而言,不仅仅节省了更多的时间和修复成本,而且它可以提高你的信心,愉悦程度和生产力。

w#j'Y!M[ TM#Wm0

A9n-g mP&II2l$e0  现在你已经决定开始写单元测试,那么你可能会为如果开始而困扰。最直接的回答就是为一些已存在的代码写测试用例。不幸的是,通常这都比较困难。一部分原因是写测试本身需要一些经验,通常第一次写都不是那么正确。然而还有一个原因是:代码本身对测试不够友好。

.Mu%r'hZcW9c O)]051Testing软件测试网NB(d Q$?J;Nhu

  可测试性例子:计算时间差值

,\7ub!V X1j}zHy051Testing软件测试网 T d3}ZUn

   “可测试性”是一个衡量特定接口是否对测试友好的方式。一个对测试友好的接口会让外部比较方便地访问到那些有趣的部分,而且不需要请求不相关的部分,从 而可以测试任意一个给定的API。换句话说,可测试性是一个衡量接口设计是否良好,是不是做到了低耦合和高内聚,这些都是一个好的方式来判断这个对象是否 足够独立于其他对象,并且每个对象/函数是不是只做一件事情,并且运行良好。

%a*tI.{3s5Bf bJ051Testing软件测试网y_3M{U0W7L&c0J

  作为一个可测试性的例子,我们将回到之前的jQuery插 件。在我们的前两个单元测试用力中,我们想要去确保8天前的日期能返回字符串“1 week ago”,而且其他时间也可以返回更加准确细致的字符串。注意这些都不能应用在DOM元素上,我们需要创建一个元素来测试日期的差值计算和返回字符串的友 好展现。51Testing软件测试网n.t c+s.R p/d

51Testing软件测试网-k]J}"\

  jQuery插件本身比以前更加难以测试,最大的原因就是它做了不止一件事情:他计算了两个日期的不同,生成一个友好可读的差值展现并且从一个元素中读取日期并用innerHTML写入到DOM节点中。51Testing软件测试网)e$a:c;W,k3]]

-`1H)R*`GR!BCD"O4bSf%E0  为了处理这些问题,留意下面的代码,它是同个插件的另一种实现:51Testing软件测试网f%^i W1^'{K(T

51Testing软件测试网Ku&Jy|_

51Testing软件测试网 F4QErq(X'Fyf3X

var dateUtil = {};51Testing软件测试网:Jh(`*S}S
(function () {
$l)R/C1F?Hm c2f0 var units = {51Testing软件测试网%W`d9R9X dr|:F
 second: 1000,
ZDQ {0g5ANq0 minute: 1000 * 60,51Testing软件测试网I3L mmK+U)pR
 hour: 1000 * 60 * 60,
hol0`I&K{0 day: 1000 * 60 * 60 * 24,
;R:a jf*p/~_6H H4mf0 week: 1000 * 60 * 60 * 24 * 7,51Testing软件测试网 rV#\9TbDd
 month: 1000 * 60 * 60 * 24 * 3051Testing软件测试网6Y Io.n$j6T@%E
 };
`^^\tD^0 function format(num, type) {51Testing软件测试网Y#ud*u._R]
 return num + " " + type + (num > 1 ? "s" : "");
[2P*[ Ps0 }
l/iR[ks bRR0 dateUtil.differenceInWords = function (date) {
C$m0gEFJi i_0 // return correct string
.b"t%H/joY9S0 };
1@^L1n"p4Ees?j0 jQuery.fn.differenceInWords = function () {51Testing软件测试网:rs1y]PX~#AJ,lJ
 this.each(function () {51Testing软件测试网UC'qV,L(R${
 var datetime = this.getAttribute("datetime");
_;N3QemmDB7L0 this.innerHTML = dateUtil.differenceInWords(new Date(datetime));
lp Upd+[fdB0 });
*E\]/LE B-K.B g0 };51Testing软件测试网T1e)e7A+YN"w
}());

l+xF+] n5I8ta0  这个代码和之前是一样的,只不过是进行了一次重构。上面的代码含有两个公用的函数:jQuery插件和新的 dateUtil.differenceInWords,这个函数调用了一个日期,然后返回一个对人有好的字符串,用于表示日期是多久之前的。还是不够完 美,但是我们已经有两个分开的关注点。现在jQuery插件只负责替换元素的innerHTML为给定的友好字符串,新的函数则负责计算新的字符串。老的 测试用例依然能检测通过,但是为新的接口写测试用例会变的更容易:51Testing软件测试网 q5s!o&@9lA:W

pm~ lG_!N;Jr051Testing软件测试网wbPrCiv"W"f

TestCase("TimeDifferenceInWordsTest", {51Testing软件测试网%jm szA(w4uz
 setUp: function () {
U;~IL@$G tT yJ/h0 this.date8DaysAgo = new Date(new Date() - 8 * day);51Testing软件测试网4Iy+L;|;FM QNC
 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网!m1[5{x1f0MX0[7H
 this.date3DaysAgo = new Date(new Date() - diff);
_l7b[*o]:qn0 },
lb4@eQT+B_0 "test 8 day difference should result in '1 week ago'": function () {
BC.WQsvN8K0 assertEquals("1 week ago", dateUtil.differenceInWords(this.date8DaysAgo));
} Brz:C4K3Wn:P0 },51Testing软件测试网8Dd.goXm9myGJ
 "test should display difference with days, hours, minutes and seconds": function () {
W S)LjP2j/| F _e0 assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago",
jf@WL0 dateUtil.differenceInWords(this.date3DaysAgo));
-x!R8RAGt0 }51Testing软件测试网 {4cJ!jskY$X
});

H8HKm ]9j3R5s0  现在我们的测试中已经不包含任何DOM元素,然后我们可以更加高效地测试生成字符串的逻辑。和之前的类似,测试jQuery插件只是一项确保文本内容是否正确替换的工作。51Testing软件测试网 v.xjqR3\9`

51Testing软件测试网-b3q UT&D/x

  为什么要为测试修改代码?51Testing软件测试网Kv#`:GaY

u/xs(]vT[4z E3]0  每一次我给一些人介绍测试并解释可测试性的原理时,我总会听到一些质疑声,比如“你不仅仅想让我花时间来写测试,而且你还想为这些测试修改代码?”51Testing软件测试网9[4Q[-|/jR N^ G

~Ft2N psrQ)b%B0  看看我们在时间差只代码中所做的。改变的目的就是减轻测试的工作量,但是仅仅是对测试有帮助么?相反,我们的改变还能让代码更容易从不相关的行 为中分离出来。现在,如果我们在后来决定在页面中实现比如一个Twitter的订阅功能,我们可以直接使用differenceInWords函数而不是 通过DOM元素和jQuery插件寻找一个笨拙的方式。51Testing软件测试网f&Z/[2[ gA*s_

J:m0x4l _0  可测试性是一个好的设计的固有特点。你可以同时保证可测试性和不好的设计,但是当可测试性差的时候,就一定不是一个好的设计。回想那些作为小例子的测试——使用你的代码的例子——如果测试比较困难,那么这也意味着你的代码难以使用。

-{4GT | HN6S%P0

TAG:

 

评分:0

我来说两句

Open Toolbar