单元测试普及(二):更高效地检查bug

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

8j o `3rg$jog)D0  如果你没有阅读过前一篇文章,请移步

(]1o5] yI^ a8ak0

Q1]*^8}$o&m-P;SA0  ●单元测试普及(一):以前的测试方式51Testing软件测试网/y)uC iQcVZ3Y1` Hr

"n9Q)]o Q.?W0  单元测试是一种查找bug和验证程序正确性的测试方式,并且不需要纠结于调试工具和console.log/alert。单元测试还带来很多其他优点,我会在本文中讲述。51Testing软件测试网$d_4h fT.bi/^/D4Kp

51Testing软件测试网!?n7P1GU]|5|n

  什么是单元测试51Testing软件测试网7?@9BgfA$t)l

51Testing软件测试网a7d9G[S

  单元测试代码通常伴随着一个期望值运行在你的产品代码中。举个例子,我们假设之前jQuery.fn.differenceInWords例子中的两个bug还没有修复,然后试着用单元测试来查找Bug:51Testing软件测试网2CG$ii^#X8jfd

var second = 1000;
6c'~^#A5{is0var minute = 60 * second;
5u1[*Vu(w? Jd ID|-D0var hour = 60 * minute;51Testing软件测试网:^3Tnn;O^R
var day = 24 * hour;
V*_ fU8H$rK$][0try {
AEe7u5?0 // 测试8天的差值结果是否为 "1 week ago"51Testing软件测试网%R;MO"S?A*{/i9sT
 var dateStr = new Date(new Date() - 8 * day).toString();
Z?g&R)nNW0 var element = jQuery('Replace me');
p^@0C#]O U0 element.differenceInWords();
(LM'F PX&^l0 if (element.text() != "1 week ago") {51Testing软件测试网-zI*zI,qw\7\
 throw new Error("8 day difference expected\n'1 week ago' got\n'"+51Testing软件测试网C5^7{gwyP[
 element.text() + "'");
V]+e:iBb0 }
)e R Oij,_0 // 测试一个更短的日期
%fa,aPu0 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网7^:goe D%U
 dateStr = new Date(new Date() - diff).toString();
b[-x/F'j0 var element = jQuery('Replace me');
7M@VZ(TX]/mfG0 element.differenceInWords();51Testing软件测试网^Ho'vv5RTg
 if (element.text() != "3 days, 2 hours, 16 minutes and 10 seconds ago") {51Testing软件测试网zM5K k:f$dq/z
 throw new Error("Small date difference expected\n" +51Testing软件测试网*Zv mXp
 "'3 days, 2 hours, 16 minutes and 10 seconds ago' " +51Testing软件测试网"_ Tsf_
 "got\n'" + element.text() + "'");
MZ3M YH:F^n0 }51Testing软件测试网 X"~{3R*e&[k%y
 alert("All tests OK!");51Testing软件测试网M\-uE'MdV
} catch (e) {51Testing软件测试网5N @#_nx&vcu9K
 alert("Assertion failed: " + e.message);51Testing软件测试网ht5P!FRj8tPxY
}
51Testing软件测试网L k[ Q)}9{

  上面的测试用例用 已知的日期属性值对元素进行处理,然后如果结果和期望值有出入,则抛出一个错误。这些测试代码可以放置在另外的文件中,在使用这个插件的页面中将这个文件 也一起载入进去。在浏览器中运行这个页面,我们就可以看到提示“All tests Ok!”,或者一个注明错误位置的消息。51Testing软件测试网pAZ AvX!O

51Testing软件测试网~4YC^2s}\

  这样的测试方式看起来可能会有些麻烦。我们不仅仅需要写log语句来检查代码,而且我们还需要创建元素,然后通过运行这个插件来检查生成的文本。这个测试方法的优点在于:51Testing软件测试网 scY:si2|"C

QsoM"v6P N{0  ● 这个测试可以在任何时候任何浏览器中运行。

[#P8H fW'Qv7[E0

k [2Ci4U0  ● 只要我们记得在修改代码之后运行这个测试用例,那么这个bug基本上不可能再次出现。

.z#f0V6P;]@h%DH0

a.m VfMCjj0  ● 如果能正确地清理代码,这些测试可以作为代码的文档。51Testing软件测试网Kk-O8Vl~.CBZP

*Nz.Sz6C\Z0  ● 测试可以自动进行。无论我们增加了多少测试,我们依然只需要一个页面来检查是否存在问题。

P;y+f4KOy,b:QN0

$Hb Yb(kqr0  ● 测试不会干涉到产品代码,因此不需要冒着像alert或者console.log方式可能带来的风险。51Testing软件测试网UPQ1}[8C

$y;?0`B q0  使用单元测试框架51Testing软件测试网'P8q/r NC v

51Testing软件测试网9^^,Dl.Es5Sc

  我们所写的测试包含了比较多的代码。幸运地是,现阶段存在很多测试框架让我们从大量测试代码中解脱出来。使用一个测试框架可以让我们减少测试本身包含的逻辑,从而减少测试本身出现bug的概率。一个框架可以提供更多自动测试和展示结果的选择。51Testing软件测试网:tWE ]5|7u

51Testing软件测试网4~f;rT3e'D#y)Ub

  Assertions

;S'D/a D%D051Testing软件测试网m;DYT Ma

  assertion就是一种特殊的检查参数的方式,并且可以做到错误的标记(通常采用抛出一个Assertions或者类似的方式)。最简单的assertion就是判断参数是否正确。assertions通常接收一个message,用于在出错时展示:51Testing软件测试网Wk/z lqJ'K5@

u;w,Z [0y051Testing软件测试网\6a\ZY q8eR+s

assert("Small date difference expected\n '3 days, 2 hours, 16 minutes and " +51Testing软件测试网#n `J h aZ
 "10 seconds ago' got\n'" + element.text() + "'",51Testing软件测试网n/iM YB9{!znO
 element.text() == "3 days, 2 hours, 16 minutes and 10 seconds ago");

)\2i%s9x3PT9j$@0  assert方法调用message作为第一个参数。message的意义在于测试需要预先设置好期望值,然后assertion就像是一个伴随message的规范来界定结果是否和期望值一致。

5qnb3C dpN!lBAU LM0

R/W%lsn9[ w4W?/K0  一个简单的assert,就像上面的例子一样,通常就可以满足你的需要了,大部分测试框架都提供了一个可定制的assertion。我们真正需要做的是检查一些计算结果是否和期望值一致。大部分测试框架都含有一些类似assertEquals的方法,例子如下:51Testing软件测试网*we _OL a

*|{H8Oe$~ q yV S,u0

y{3c)Ju-D2`c:l&u^0
assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());

~4Ms(oj_0  注意,我们不需要再说明判断形式。assertEquals知道我们期望第二个值和第一个值对等,那么它会自己生成一个合适的message。

@U4dA$M4T$a0

Wt*\v Q Y A GZ0  测试用例,setUp和tearDown

}K&\VLQ8^5E0

c5b/y5J+|3WZ0  我们手工编写的单元测试包含两个独立的测试。当使用一个测试框架的时候,我们通常在测试用例将其指定为一个独立的函数。一个测试用例就是一个测 试的集合,用于测试相关的函数。为了让测试报告更方便查看,测试用例一般都会有一个名字。下面就是一个结构化之后的手工单元测试例子。

Dqr3I#R$qH051Testing软件测试网2Lr;UN4Fq+S(`*~

P!Mk6hJ0Iy`-mv0
var second = 1000;51Testing软件测试网wl|)w[y#@
var minute = 60 * second;
9W\ eY y4I,A0var hour = 60 * minute;51Testing软件测试网[9I d&~P(LlD(duy
var day = 24 * hour;51Testing软件测试网.dG4d`N`,LX5Z;W`
TestCase("TimeDifferenceInWordsTest", {
9b)R.T.U'`Yj*X0 "test 8 day difference should result in '1 week ago'": function () {
3Jt_i.b%lJ @0 var dateStr = new Date(new Date() - 8 * day).toString();51Testing软件测试网{b/u.aW K#w \
 var element = jQuery('Replace me');
x0m2H,A Ou0 element.differenceInWords();
"MqyQj%~0 assertEquals("1 week ago", element.text());51Testing软件测试网o.q$V ~sC4L'p+D v
 },51Testing软件测试网!k!Q pjR){@
 "test should display difference with days, hours, minutes and seconds": function () {51Testing软件测试网+sY'q5J:L
 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网U\4i*]+jTv
 dateStr = new Date(new Date() - diff).toString();51Testing软件测试网5`;zHW0E)e;Hd
 var element = jQuery('Replace me');
)EZv]6oF7N0K0 element.differenceInWords();51Testing软件测试网!{`[_Q&tOk&KR
 assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());
5p)tf[3[U!c-Q0 }51Testing软件测试网oq,Dd,`p4a
});
51Testing软件测试网:V.e,\-k@}|"zM8L

  每个测试之前的注释都换成了测试函数的名字,比较处也换成了assertion。我们甚至可以让每一个测试更加清晰,通过将date对象的创建放到一个指定的方法setUp上,这个方法在测试函数执行前会被调用:51Testing软件测试网7X3O-Vo9cq ["S

51Testing软件测试网+jNZ(@,Q E~M.jqv#|8W

51Testing软件测试网?Q7u"q|D

TestCase("TimeDifferenceInWordsTest", {51Testing软件测试网r(T2A2uwQ?+I(O4xw
 setUp: function () {51Testing软件测试网8`AaQN ?
 this.date8DaysAgo = new Date(new Date() - 8 * day);51Testing软件测试网1duCW9iW"No;@U Gq-R
 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;
7FG(D|$eg%b7^(b+p0 this.date3DaysAgo = new Date(new Date() - diff);
0^+SIM~0 },
c&j#G#L8N O+FB br0 "test 8 day difference should result in '1 week ago'": function () {51Testing软件测试网C ^!u xpfO!A
 var element = jQuery('Replace me');51Testing软件测试网P0w.hJ0[@p
 element.differenceInWords();
3i b;Rj8{Pq D0 assertEquals("1 week ago", element.text());
nqM%q.i;?/V0 },
dPw^'q!q uLj+R0 "test should display difference with days, hours, minutes and seconds": function () {
GB aO6}b\7dEi0 var element = jQuery('Replace me');
FE1k{?%CM[0 element.differenceInWords();
j})ea!N_p8x0 assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());
q C2N%i!}AX Cu0 }51Testing软件测试网-P%AT1L$j,wnc7P@%K8A
});

)j5N2e)z0eR&m0  setUp方法也可以包含一个附带的tearDown方法,在每个测试之后执行。这个例子不需要tearDown方法,但是你可以在需要在每次 测试完成之后需要做清理的时候增加这个方法。假设你要测试一些实现本地存储中数据缓存的代码。为了避免测试之间的相互影响,你可能会想要对测试产生的数据 进行清除。51Testing软件测试网)l7~@;uKWD

?8Y'xcU V%q#x0  除了代码和测试之外,你需要指定一些方式来执行测试。大部分JavaScript单元测试框架都要求有一个简单的HTML文件以正确的顺序加载 正确的文件(包括测试框架本身)。这个HTML文件可以在浏览器中加载。通常所有通过的测试都用绿色标记,然后不通过的测试会用红色标记。51Testing软件测试网)~g H ]} K'h


TAG:

 

评分:0

我来说两句

Open Toolbar