使用 Test Cases
YUI Test最基础的是YAHOO.tool.TestCase对象。可以使用YAHOO.tool.TestCase的构造函数创建一个TestCase对象,创建对象时可以传递一个包含方法和其他信息的对象来初始化测试用例。例如:
使用这些代码,如果抛出了一个错误类型TypeError,错误信息为"Expected an array"的错误,方法testSortArray()才能通过测试,如果其他类型的错误产生了,测试会由于未期待的错误而失败。
注意:如果测试标记了一个期望的错误,除非抛出了指定的错误不然测试将失败。如果测试完成了但没有抛出一个错误,那么测试是失败的。
Assertions
测试方法使用断言去检查一个特定的动作(particular action)或一个函数的合法性。一个断言方法用来测试一种条件是不是正确的。如果不正确,它将抛出一个错误致使测试失败。如果在一个测试方法中所有的断言都通过了,也就是说这个测试方法通过了。为帮助写测试,YAHOO.util.Assert对象包含了一些可以用来验证数据有效性的断言方法。
这部分覆盖了一下主题:
相等断言
相等断言中最简单的断言方法是areEqual()和areNotEqual()。这两个方法都接收三个参数:期望值,实际值和一个可选的错误信息(如果该参数被省略了,将会产生一个默认值)。示例:
这些方法使用两个等于号(==)去决定两个值是否相等,所以可能发生强制类型转换。由于两个等于号会在比较之前把数字转换为字符串,这就意味着字符串'5'和数字5会被认为是相等的。如果为了测试的目的你不想值被转换,你可以使用全等断言来代替。
全等断言
全等断言的方法有areSame()和areNotSame(),这些方法接收的参数和相等断言是一样的:期望值,实际值和一个错误信息。和相等断言不同的是,这些方法使用三个等于号来进行比较,以保证不会发生强制类型转换。示例:
注意:尽管这个示例显示了多个断言会失败,但只要一个断言失败了,测试就会停止,致使其他会被跳过。
Data Type Assertions
有时一些数据应该为特定的类型。为了在这种情况下提供帮助,那里有一些方法用来测试变量的数据类型。每个这样的方法接收两个参数:将被测试的数据和一个错误信息。有如下的数据类型断言:
以下实例将演示他们是如何使用的:
如果你需要测试一个对象的类型而不是简单数据类型,你可以使用isInstanceOf()断言,这个方法接收三个参数:将要测试的构造函数,将要测试的值和一个可选的错误信息。这个断言使用instanceof运算符来觉得测试通过还是失败。示例:
特殊值断言
在javascript代码中有几个特殊可能产生,包括true, false, NaN, null和undefined。这里有很多断言被设计用来对这些特殊值进行测试。
每个方法都接收两个参数:将被测试的值和错误信息。所有的这些断言都期待确切的值(不会发生类型转换),例如调用isFalse(0)将会失败
强制失败
很多测试方法会由于断言的结果而失败,然而有时你也想强制一个测试失败或者创建自己的断言方法。为了达到这些目的,可以使用fail()方法立即强制一个测试方法失败
这种情况下,方法testForceFail()除了强制方法测试失败外不做任何事情。你可以选择传递一些信息到fail()方法,这些信息将作为错误信息进行显示。
当这个方法的错误被报告时,信息"i decided this should fail"将会被打印。
Simulating User Actions
可能由于网页应用程序提供交互的级别,简单的函数调用测试可能不足够。自从一些操作需要用户区触发它们,YAHOO.util.UserAction对象提供了一些方法用来模拟基本的用户使用键盘和鼠标触发的动作。
模拟事件是浏览器创建的事件,大部分时间,和用户触发的事件是一样的。事件会正常的冒泡并且事件对象的属性拥有event对象中的数据(有时这些属性是特定于浏览器的,所以建议你使用YAHOO.util.Event这个浏览器均衡(browser-equalizing)的方法去给属性获得合适的值,比如target, relatedTarget和charCode。) 在事件的生命周期内所有的事件处理函数都是被同步调用的。
Mouse Events
这里有7个鼠标事件可以使用UserAction方法来模拟。
每个事件都由UserAction中相应的方法触发,这些方法接收两个参数:事件目标对象和一个为事件指定额外信息的对象。为了模拟在document.body上的click事件,例如,以下代码可以实现:
这个代码模拟了一个click事件,event对象拥有所有的默认属性。为了指定额外的信息,比如shift键被按下,必须使用第二个参数并且必须为event属性指定确切的DOM名称(必要时浏览器正常化逻辑(browser-normalizing logic)会转换这些为浏览器特定的属性)。
在这个更新了的例子中,模拟了document's body上的click事件,并同时按下了shift键。
其他可以额外指定的属性依赖于模拟的事件,并且它们被限制于以下列表:
detail-指示按钮触发了几次click事件(只对兼容DOM的浏览器有效)
screenX/clientY-相对于浏览器客户区鼠标事件的坐标
ctrlKey/altKey/shiftKey/metaKey-分别表示Ctrl,Alt,Shift和Meta Keys的状态(true代表按下,false代表没按下)
button-触发事件时按下的鼠标键,0代表左键(默认),1代表右键,2代表中间键。
relatedTarget-鼠标从哪个元素移入(在mouseover事件期间)或移出(mouseout事件期间)。你应该使用YAHOO.util.Event.getRelatedTarget()从生成的event对象中去获取该值,因为在必要时它会转换为浏览器特定的属性名。
不同方法以及它们额外属性的示例:
Key Events
使用UserAction可以有效的模仿以下三种按键事件:
和鼠标事件一样,每按键事件都有相应方法,并且名称是一样的,这些方法接受两个参数,一个是事件的目标对象,另外一个是为event指定额外信息的对象。对于按键事件,第二个参数是必须的,你必须指定在和哪个键进行交互。对于keyup()和keydown(),keyCode属性必须被指定;对于keypress(),必须包含charCode属性。在很多情况下,对于相同的键,keyCode和charCode的值是相同的(例如97,是键盘'A'的键值,也是字母'a'的ASCII值)。示例:
按键事件也支持event中的ctrlKey, altKey, shiftKey和metaKey属性。
注意:由于浏览器的差异,在所有的浏览器中模拟按键事件的方式可能不同。例如,当在textbox中模拟keypress事件时,只有在Firefox中会把被模拟按下的字符更新到textbox中。对于其他的浏览器,事件照样会注册,处理函数也会执行,然而textbox的显示和value属性都不会改变。在将来浏览器对模式事件的支持改善后,这些差异应该被消除。
Safari 2.x开发者们:由于在Safari 2.x基类代码中存在一个bug,模拟keydown事件可能导致浏览器崩溃。这个问题在Safari3.x中已经解决。
Asynchronous Tests
YUI Test允许你暂停当前正在运行的测试,并在一段时间后或者特定的事件恢复运行。TestCase对象拥有一个wait()方法。当wait()方法被调用时,测试立即退出(意味着在那行代码之后的其他代码都会被忽略掉)并等待一个信号去恢复测试。
通过传递两个参数到wait()方法中,一段时间后一个测试可能恢复运行。这两个参数为:一个是要执行的函数和一个是在执行这个函数前等待的毫秒数(和使用setTimeout()是相似的)。在指定的时间过后作为第一个参数传进去的函数会作为当前测试的一部分运行(在相同的作用域)。示例:
在这个代码中,testAsync()函数执行完一个断言后,等待1000毫秒再执行另外一个断言。通过wait()方法,使函数仍在原来测试的作用域内,所以它可以像原来测试中代码一样访问this.data数据。没有事件指示何时恢复测试的情况下,等待一段时间让测试继续运行还是很有帮助的。
如果你想在指定的事件发生时才恢复测试,你可以调用wait()方法但不带任何参数。这时,只有调用了resume()方法,测试才会恢复。resume()方法接收一个参数,即当测试恢复时运行哪个函数。这个函数应该指定额外的断言。接下来的测试看Anim对象是否完成了它的动画。
在这个示例中,使用一个Anim对象对一个元素的宽度设置为400px产生动画。当动画完成时,会触发onComplete事件,在onComplete事件处理函数中会调用resume()方法。通过rerume()方法,函数简单的测试了元素最终宽度是不是400px.请注意,为了让代码正常运行,在subscribe()方法中,我们必须通过第二个和第三个参数调整事件处理函数的作用域。一旦设置好事件处理函数,动画就开始执行,接着不使用任何参数调用wait()方法。这时,测试会暂停直到动画完成和resume方法被调用。
TestSuites
对于大型的网页应用程序,在测试期间你可能有很多测试用例需要运行。test suite可以帮助对测试用例按功能进行分组,一组测试用例可以一起运行。可以使用YAHOO.tool.TestSuite的构造函数,传递test suite的名称来创建一个新的test suite实例。传递的test suite名称是为了日志的目的,它也可以让你分辨哪个TestSuite正在运行。例如:
这里,创建了一个test suite,并通过add()方法添加了三个测试用例。现在这个test suite包含了去运行一系列测试所有的信息。
你也可以使用add()方法在一个父类TestSuite实例中添加另外多个TestSuite实例:
通过在父类test suite中把多个test suite分组在一起,你可以更有效的管理测试一个应用程序的特定方面。
test suite也有setUp()和tearDown()方法。test suite的setUp()方法会在第一个测试用例的第一个方法之前执行(在测试用例的setUp()方法之前执行);test suite的tearDown()会在所有的测试用例/测试套件中的所有方法执行后才执行(在测试用例的tearDown()方法后执行)。为了指定这些方法,可以在YAHOO.tool.TestSuite构造函数中传递一个对象字面量:
对于多个测试用例和测试方法都需要的数据,test suite的setUp和tearDown方法在设定全局对象可能很有帮助。
Running Tests
可以使用YAHOO.tool.TestRunner对象去运行测试用例和测试套件。这个对象是一个单例对象,可以用来简化测试用例和测试套件内的测试,简化测试成功和失败时的回归报告。通过add()方法往TestRunner中添加测试用例/测试套件,以决定哪些测试用例和套件将被运行。然后调用run()方法去运行测试用例。
如果有些时候你决定不去运行已经添加到TestRunner中测试, 可以调用clear()方法移除他们。
执行这个调用将移除所有已经通过add()方法添加的测试用例和测试套件。
TestRunner Events
TestRunner提供结果和一些公开的事件处理的信息。这些事件可以在你感兴趣的4个不同点发生:测试阶段,测试用例阶段,测试套件阶段,TestRunner阶段。每个事件中的有效数据完全依赖于事件的类型以及事件发生的阶段。
Test-Level Events
Test-level事件在特定的测试方法执行时发生。这里有三个test-level事件:
对于每个事件,事件的数据对象都有三个属性:
type-指示发生了什么类型的事件
testCase - 当前正在运行的测试用例
testName - 刚被执行或忽略的测试的名称
对于TestRunner.TEST_FAIL_EVENT,有一个error属性包含一个error对象,就是这个error对象致使测试失败。
TestCase-Level Events
在测试用例阶段有两个事件会发生:
对于这两个事件, 事件数据对象包含三个属性
对于TEST_CASE_COMPLETE_EVENT事件, 还包含一个results额外的属性。results属性是一个对象,包含测试用例中所有测试结果的汇总(它不包括被忽略了的测试的信息)。每个运行过的测试在result对象中都有一个实体,实体中的name属性和测试方法的名称是一样的,实体中的值是一个对象包含两个属性:result, 它的值为"pass"或者"fail",和message,一个描述result的文本描述(很简单,测试通过时为"Test passed",或者测试失败时的错误信息)。failed属性指示测试用例中多少个测试失败了,passed属性指示多少个测试通过了,total属性指示多少个测试执行了。一个典型的results对象和这个很像:
TEST_CASE_COMPLETE_EVENT提供这些信息为了是测试过程透明化。
TestSuite-Level Events
在测试套件阶段有两个事件会发生。
对于这两个事件,事件的数据对象包含三个属性:
TEST_SUITE_COMPLETE_EVENT也有一个results属性,其中包含了测试套件的中所有测试用例(和其他测试套件的)的结果的汇总。主套件中的每个测试用例和测试套件都在results对象中有一个实体,形成了数据的分层结构。一个典型的results对象和这个很像:
这个示例显示了一个测试套件包含两个测试用例的结果,但是也有可能一个测试套件包含其他测试套件。在那种情况下,也会建立相应的分层结构,示例:
在这个代码中,测试套件包含了一个名为"testSuite0"的测试套件,被包含的测试套件以及它里面的测试用例都包含在results中。在每个阶段,结果都是被汇总了的,以便你能说出每个测试用例或测试套件中有多少测试通过了,多少个失败了。
TestRunner-Level Events
在TestRunner 阶段有两个事件发生:
这些事件的数据对象包含一个type属性,指示什么类型的事件发生了。COMPLETE_EVENT事件也包含了一个results属性,它的格式和TEST_SUITE_COMPLETE_EVENT事件返回的数据格式是一样的,其中包含了所有的添加中TestRunner中的测试套件、测试用例的信息的汇总。
Subscribing to Events
你可以通过调用subscribe()方法订阅特定的事件(请查看documentation)。你的事件处理函数应该期望一个单独的对象作为参数传进来。这个对象提供了刚发生事件的一些信息。至少,这个对象包含一个typ属性,告诉你发生了什么类型的事件。例如:
在这个代码中,handleTestFail()函数作为TEST_FAIL_EVENT的事件处理函数。你可以使用一个事件处理函数来订阅多个事件,使用事件数据对象的type属性来决定去做什么:
Viewing Result
为了检视测试的结果,需要创建一个新的YAHOO.tool.TestLogger对象。TestLogger是Logger组件的子类,被设计用来输出TestRunner的结果。在调用TestRunner.run()之前,创建一个TestLogger实例确保所有的结果会被报告。
一旦创建,你就可以过滤数据,只显示测试通过的或测试失败的信息等等。
Test Reporting
当所有的测试已经完成并且results对象已经返回,通过YAHOO.tool.TestReporter对象可以把results传送到服务器端。TestReporter对象创建了将传送到指定的URL的表单域,表单域中包含以下字段:
你可以通过传递一个URL地址作为参数来创建一个新的TestReporter对象,报告将发送到该URL地址。然后可以把results对象传递进report()方法进行提交。
表单域的提交将在后台执行,不会造成页面的跳转。这个操作时单方向的,reporter不会从服务器端获取任何返回信息。
Serialization Formats
这里为results对象预先定义了两种序列化格式:XML(默认)和JSON。你可以通过传递YAHOO.tool.TestFormat.XML或者YAHOO.tool.TestFormat.JSON到TestReporter构造函数中指定序列化格式。(如果没有指定参数,将默认使用YAHOO.tool.TestFormat.XML格式):
XML格式将使用一下格式输出results
JSON格式需要在也页面中装载JSON utility模块,将使用对象/数组分层结构的方式输出results对象。比如:
每种格式产生的字符串都不会带有额外的空格(这里显示的空格和缩进只是为了阅读的目的)
Custom Fields
在results被提交时,你也可以使用addField()方法添加额外的字段发送到服务器端。这个方法接受两个参数:名称和值。任何通过addField()方法添加的字段会随默认字段提交到服务器端:
注意,如果你指定的字段名和默认字段是一样的话,自定义字段将为忽略,默认字段将被提交。
support&Community
YUI类库以及相关的主题可以在YUILibrary.com.forums讨论
此外,确保检视YUIBlog获得更新,以及类库开发者写的关于YUI类库方面的文章。