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

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

51Testing软件测试网)SLQ/O _2Z HI rT

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

fP y Xr+l'Sf0

zBse"jS"NK0  ●单元测试普及(一):以前的测试方式

ET aA"?051Testing软件测试网p-ri.l zI;g

  单元测试是一种查找bug和验证程序正确性的测试方式,并且不需要纠结于调试工具和console.log/alert。单元测试还带来很多其他优点,我会在本文中讲述。

"I4\C)r&d0

OFj'B,iE$]N)IZ0  什么是单元测试51Testing软件测试网1Fu4~ I;G"P GJ

51Testing软件测试网%[_9X8X9Xv/Q3PC-T4{8a

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

var second = 1000;51Testing软件测试网A'N)P5x*UDv;Q
var minute = 60 * second;
(] hpjo0var hour = 60 * minute;51Testing软件测试网XQn&D0A.F
var day = 24 * hour;
+OaA%q7y,y#gY0B0try {51Testing软件测试网`K"l.p ny kM
 // 测试8天的差值结果是否为 "1 week ago"51Testing软件测试网.M@k$[} R
 var dateStr = new Date(new Date() - 8 * day).toString();51Testing软件测试网e)r8P/Yc%h?i`N(~
 var element = jQuery('Replace me');51Testing软件测试网^K2h C1y~9L
 element.differenceInWords();51Testing软件测试网3\ wL)u WSjP
 if (element.text() != "1 week ago") {
&|Vy&z1P+mw{u0 throw new Error("8 day difference expected\n'1 week ago' got\n'"+
(Y;ItuR@Pg0 element.text() + "'");51Testing软件测试网qj vZ;e
 }51Testing软件测试网#R!~9w&X$y
 // 测试一个更短的日期51Testing软件测试网Y}d0QR [ f1Q;f
 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网 XhR1~w0L@R[:b m
 dateStr = new Date(new Date() - diff).toString();51Testing软件测试网sqC:Z#Q
 var element = jQuery('Replace me');51Testing软件测试网] AOp^Zw
 element.differenceInWords();51Testing软件测试网:Q+d ?j N7v7U
 if (element.text() != "3 days, 2 hours, 16 minutes and 10 seconds ago") {51Testing软件测试网QjH'O;Hk
 throw new Error("Small date difference expected\n" +51Testing软件测试网;nB!nt;ep(T'dd
 "'3 days, 2 hours, 16 minutes and 10 seconds ago' " +
iU @!DO6Q0 "got\n'" + element.text() + "'");
1oZ7c2F!Lh#g-I^0 }
w7C/n D}E\ GJ6d|0 alert("All tests OK!");51Testing软件测试网q'L;t4Zg#k
} catch (e) {51Testing软件测试网$|vo3E~"l G
 alert("Assertion failed: " + e.message);51Testing软件测试网1V1N!A"sX(b1^
}
51Testing软件测试网.c`[8SR

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

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

5T/Xm0t{Jv0

(B\IM[ ?-b0  ● 这个测试可以在任何时候任何浏览器中运行。51Testing软件测试网)Ph SGHu4b

51Testing软件测试网%qd"G,r |ev@B6N

  ● 只要我们记得在修改代码之后运行这个测试用例,那么这个bug基本上不可能再次出现。51Testing软件测试网r9v!pWp9S"beUD

51Testing软件测试网bN2lgH

  ● 如果能正确地清理代码,这些测试可以作为代码的文档。

9[^"n @wTw#A051Testing软件测试网-u@TDm6X

  ● 测试可以自动进行。无论我们增加了多少测试,我们依然只需要一个页面来检查是否存在问题。51Testing软件测试网h#h E T3oL0GX/r!R

F&g'T:c'U0  ● 测试不会干涉到产品代码,因此不需要冒着像alert或者console.log方式可能带来的风险。

;OaYWB c051Testing软件测试网-g}E2wM

  使用单元测试框架51Testing软件测试网 wz0Dui

51Testing软件测试网;f4f:pc|

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

B5w5i5d ^6a(rH0  Assertions

i&cP2Cp'F9c&p051Testing软件测试网)Ru'sbIQ _F*v0K

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

51Testing软件测试网[RUd%c

51Testing软件测试网| s uCiZ)E;je e2dNw

assert("Small date difference expected\n '3 days, 2 hours, 16 minutes and " +51Testing软件测试网Q%}-u'k(p)E
 "10 seconds ago' got\n'" + element.text() + "'",
Q1Z_ad^L0 element.text() == "3 days, 2 hours, 16 minutes and 10 seconds ago");

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

QO@;y,f0

'ioak#d.N0  一个简单的assert,就像上面的例子一样,通常就可以满足你的需要了,大部分测试框架都提供了一个可定制的assertion。我们真正需要做的是检查一些计算结果是否和期望值一致。大部分测试框架都含有一些类似assertEquals的方法,例子如下:

7\ K1Y7Rlq#WL K K051Testing软件测试网]OV-c!cNp/PB

n_O"U;X?0
assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());
51Testing软件测试网 db0N8w'M}*Y

  注意,我们不需要再说明判断形式。assertEquals知道我们期望第二个值和第一个值对等,那么它会自己生成一个合适的message。51Testing软件测试网d AC!Y1P5@j

yt @7FF3Nj1OH0  测试用例,setUp和tearDown51Testing软件测试网 y)qs5M{s

51Testing软件测试网sG:Oz"Pua

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

51Testing软件测试网]8aH3T&G'S(uzK_

2W'Zqs(fa0H bG6A0
var second = 1000;
/}-fcr,F0B d0var minute = 60 * second;51Testing软件测试网"t/I,~x ~6r
var hour = 60 * minute;
FifT^C ?w)t0var day = 24 * hour;
5f@ @&m+W^ l6r0TestCase("TimeDifferenceInWordsTest", {
ehs1F\^0 "test 8 day difference should result in '1 week ago'": function () {51Testing软件测试网6}8uX#o/AK.h0K4y*G
 var dateStr = new Date(new Date() - 8 * day).toString();
t]G.pl-n.W0 var element = jQuery('Replace me');51Testing软件测试网#X&DRq!VYb
 element.differenceInWords();51Testing软件测试网~'Zu1_!G+@`
 assertEquals("1 week ago", element.text());
d+l"B1YP PO0 },51Testing软件测试网 UXT4i^5Z
 "test should display difference with days, hours, minutes and seconds": function () {51Testing软件测试网*u]ZGN|
 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网 v3L5HgR R
 dateStr = new Date(new Date() - diff).toString();51Testing软件测试网+oAA,b+x"XA
 var element = jQuery('Replace me');
:yVp%s1@3o0 element.differenceInWords();
Q Lm*g|0 assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());51Testing软件测试网 Jv:LOM^
 }51Testing软件测试网'V%Qbnb q"[ ZY4D
});
51Testing软件测试网y'lQtpCP m(nD

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

!Eow#h'K+k0

-rnH(e#ZJ&DO051Testing软件测试网"tz{!U!E.H

TestCase("TimeDifferenceInWordsTest", {
7]7fS L1Bd0 setUp: function () {51Testing软件测试网hB x| jY
 this.date8DaysAgo = new Date(new Date() - 8 * day);
,TXm`$Pm G0 var diff = 3 * day + 2 * hour + 16 * minute + 10 * second;51Testing软件测试网&n!Q"d WexMu
 this.date3DaysAgo = new Date(new Date() - diff);
h t5hg:{|E0 },
`1j?/Mz~vP0 "test 8 day difference should result in '1 week ago'": function () {51Testing软件测试网J`6?^~]w J|-Po `
 var element = jQuery('Replace me');51Testing软件测试网+gL*?e/O/?Y1V
 element.differenceInWords();51Testing软件测试网JwpCie8U
 assertEquals("1 week ago", element.text());51Testing软件测试网-l&N%FtV/C(_Z)hZ
 },
8sU2|YWl&Wmc6L0 "test should display difference with days, hours, minutes and seconds": function () {
_P+U:_(~[0 var element = jQuery('Replace me');
#G0O ~!C.s-eX0 element.differenceInWords();51Testing软件测试网8X#k6ZMucz l/YW!U
 assertEquals("3 days, 2 hours, 16 minutes and 10 seconds ago", element.text());
I1PIJ)q{@C0 }
M"}].u+}m0});

j!W(GD E5b6he0  setUp方法也可以包含一个附带的tearDown方法,在每个测试之后执行。这个例子不需要tearDown方法,但是你可以在需要在每次 测试完成之后需要做清理的时候增加这个方法。假设你要测试一些实现本地存储中数据缓存的代码。为了避免测试之间的相互影响,你可能会想要对测试产生的数据 进行清除。

T?8qQ+\0

m`\Uiu|2D#N0  除了代码和测试之外,你需要指定一些方式来执行测试。大部分JavaScript单元测试框架都要求有一个简单的HTML文件以正确的顺序加载 正确的文件(包括测试框架本身)。这个HTML文件可以在浏览器中加载。通常所有通过的测试都用绿色标记,然后不通过的测试会用红色标记。51Testing软件测试网"F8D U'A,yVd


TAG:

 

评分:0

我来说两句

Open Toolbar