FlexMonkey将单元测试引入Flex用户界面开发

在过去的十年里,使用自动化单元测试套件的做法已经被广泛接受,以至于当前大多数开发人员都会从事一定数量测试代码的编写,或者至少会感觉不写不好。然而 自动化单元测试的不断使用却带来了一些混乱,即谁该测试什么。开发人员是否需要在所有的代码中覆盖单元测试,如果这样做了,是不是意味着我们就不再需要专 门的QA测试人员了?许多开发团队在用户界面这块划了界线,他们认为用户界面需要很少的编码或者根本不需要编码,因此可以更经济地让专门的测试人员手工或 是使用专门的测试工具进行测试。这种分工倾向于将测试划分成“单元测试”和“功能测试”,由开发人员负责前者,而由QA测试人员负责后者。本文将探讨 Gorilla Logic公司的全新开源Flex用户界面自动化测试工具FlexMonkey,看看它是如何提高开发人员和QA测试人员生产力的。FlexMonkey允许开发者将用户界面测试纳入到单元测试套件和持续集成环境中,还允许QA测试人员将那些测试扩展到综合质量测试中。

\

虽然开发人员和QA测试人员的最终目标都是确保应用程序正常工作,但是开发人员测试的首要目标和QA还是有所不同的。开发人员测试的目标是为了保证新编写 或者修改的代码能够如愿工作而不导致“回归”(也就是说,无意中破坏了之前工作的代码)。自动化回归测试是敏捷开发中至关重要的一个部分,因为只有疯了的 开发人员才会在大量琐碎的代码重构后,不用足够的自动化测试去确保重构后的代码仍然工作。

\

我们有理由期待开发人员去测试每一个新编写的代码片段,但是将每一个这样的测试实行自动化则是不必要的。手工测试对于新的或是修改的功能而言非常高效,但 对于防止回归而言又总是不切实际。为了防止回归,开发人员必须为应用程序提供一系列自上而下并且端到端(前端到后端)的测试,另外有证据表明即使自动化测 试少到只覆盖50%的代码,它也能在很多应用中有效的防止回归。

\

QA测试比起开发人员的测试要来的更加细致,因为它的目标是确保代码能够在任何可以想到的使用场景中正常工作。换句话说,QA测试人员的任务就是通过在应 用程序上做一些可怕的事情来破坏它。当然开发人员肯定很熟悉这些所谓可怕的事情并且他们自己就可以做这方面的测试,但是这样做会使得他们真正写代码的时间 变得很少。

\

一个合格的开发人员在测试时要么采用测试优先准则,即在API本身被实现之前就创建好测试它的少量测试用例,要么采用写一点,测一点(code-a- little-test-a-little, CALTAL)的准则,即每一个开发出来的代码单元在编译完后都会马上测试。CALTAL方法在用户界面(UI)开发人员中尤其流行,但是不同于API的 在实现之前就能定义好逻辑接口的是:CALTAL在没有实际实现界面和控制代码前,并没有很好的方法来表达如何测试用户界面。

\

程序员们一般都主要依靠xUnit家族的测试框架来组织和执行单元测试。xUnit框架,例如JunitFlexUnit, 可以帮助开发人员管理大量的自动化测试套件。利用这些框架,单个测试套件可以单独的或是组合的运行,就是说为系统的某个部分开发的测试套件既可以独立运 行,也可以作为测试完整系统或整个应用中更大测试套件中的一部分来运行。此外,框架提供的综合报告使得开发人员和管理人员可以轻松的查看汇总和详细的测试 结果。xUnit测试是本身就可以执行应用程序代码,并且检查实际结果和期望结果是否一致的小程序。xUnit测试套件提供了一个简便并且高效的方法来防 止回归。大多数的生成系统,如ant,为应用程序生成过程运行将xUnit测试套件提供了直接的支持。而持续集成系统,如Cruise ControlHudson,在每一次代码提交到团队的版本控制系统后都会自动的触发这些编译,并且帮助检查团队中是否有人应该被笑话提交了不能通过测试套件的代码(这些笑话对于提高开发团队的总体效率是至关重要的)。

\

另一方面,QA测试人员主要还是依赖于可视化工具。这些工具可以录制与应用程序的交互,如鼠标点击和键盘输入,并且可以在检查结果时回放那些交互过程。过 去这些工具并不能很好的适用于开发人员,因为结果录制脚本通常非常脆弱,只要细微的改动,例如重新布局输入框或是引入了与特定脚本无关的额外界面元素,都 会导致回放失败,虽然界面更新后的应用场景仍然合乎逻辑。因此UI开发人员在测试时都趋向于“剥离”用户界面本身,而代之以编程直接调用控制代码或是生成 “合成的”UI事件。虽然这种方法不是没有好处,但是要精确的复写出与用户界面异步交互的代码却很难。这样带来的后果是需要耗费很多人力开发这种测试,并 且由于用户界面本身并不直接由测试执行,所以这种测试通常不能检验出正确的键盘和鼠标输入处理以及正确的显示数据。因此看到开发人员手工测试用户界面的情 形就很平常了。虽然UI开发人员在这种方法中也可以进行CALTAL的过程,但是用户界面却完全不需要进行自动回归测试和持续集成测试。

\

FlexMonkey是为提供鲁棒的录制和回放功能而设计的,它与商业工具,如惠普的QuickTest专业版有点类似,不同之处在于 FlexMonkey能够同时满足开发人员和QA测试人员的需要。FlexMonkey为用户交互场景提供了交互的录制和回放功能,还附带将测试保存为待 运行的FlexUnit测试套件。这些由ActionScript组成的测试可读可编辑,甚至可以不录制而通过从头开始编码实现。

\

交互地创建测试

\

FlexMonkey本身虽然是Adobe AIR应用程序,但却可以测试AIR和Flex应用程序,包括使用远程服务如BlazeDS在内的基于服务端的Flex SWF文件。FlexMonkey可以在不需要链接任何特殊测试库的情况下,录制和回放应用程序的交互,并且既可以测试单独运行的应用程序,也可以测试在 浏览器中运行的应用程序。

\

想要创建一个测试套件,你可以使用FlexMonkey加载器运行应用程序,方法可以通过文件选择对话框定位到SWF文件或者也可以指定要加载的服务器端SWF的URL。FlexMonkey将加载SWF并且将它显示在自己的窗口或者浏览器页面中,它还会打开一个包含FlexMonkey控制台的 单独窗口。该控制台主要用来管理用户界面测试的录制和修改。想要录制一个测试,你可以简单地点击Record按钮,然后与你的应用程序进行交互即可。当你 点击组件或是在应用程序窗口中输入一些字段时,每一个动作都会被录制下来并显示在FlexMonkey控制台中。下面的屏幕截图显示了一个简短的录制过 程,其中我们使用了一个简单的联系人管理应用程序(\"Monkey Contact Manager\"),输入名字(\"Fred\")和电话号码(\"555 555 1212\"),然后点击Add按钮,应用程序联系人列表中就会多出了一个新行。FlexMonkey可以如实的录制任何一个UI事件,包括许多“外部的”事件,例如选择一个嵌入在DataGrid中的ComboBox里的值。

\

be204fdd71c3f1e0780aece2716de1c8.jpg

\

在上面的屏幕截图中,我们看到在手工测试Monkey Contact Manager应用程序时,FlexMonkey控制台包含了录制的事件。

\

FlexMonkey使用熟悉的xUnit测试层次来将所有的测试组织成测试用例和测试套件。在这个例子中,我们创建了一个叫做MonkeyContactsSuite的套件,它其中包含了一个叫做MonkeyContactsCase的测试用例。这个测试用例反过来包含了一个叫做TestAddNewContact的单个测试,而这个单个测试是由我们刚刚录制完的不同用户操作组成的。对于每一个用户操作,FlexMonkey会捕获一个UI事件,一个属性值对,用以标识事件的目标以及事件相关的参数。点击第一个Input操作,我们可以看到FlexMonkey控制台右侧显示出它的详细信息,并且可以修改其中的参数。例如,我们可以在回放过程中将脚本中的输入由\"Fred\"改为\"Ethel\"。

\\

bd17d24c91110fb689cc004005516612.jpg

\

这个操作将一个带有\"Ethel\"参数的UI输入事件发送到了一个属性为automationName值为inName的组件中。换句话说,这个操作是指示FlexMonkey在回放过程中向联系人管理程序中的Name字段输入\"Ethel\"。Container Value 和 Container Property 两个字段是通过指定父容器的属性/值对来进一步验证事件的目标组件。利用目标和容器属性来查找一个组件可以很明确地引用到任何UI组件,甚至都不需要指定automationName 属性。例如,我们创建一个这样的操作:点击id为\"editPanel\"组件内部标签为\"Go\"的组件。通过点击FlexMonkey控制台上的Verify按钮(绿色的勾)打开FlexMonkey Spy Window窗口,我们可以交互性的创造一个断言来验证一系列的属性值对。使用这个spy窗口,我们可以选择UI组件上任意的属性集合并检验它们是否与想象中一样。下面的屏幕截图展示了如何使用spy窗口,来验证一系列操作后Name字段的text属性是否为\"Fred\"。

\

\

除了验证属性值以外,FlexMonkey还可以在录制的过程中捕获应用程序窗口特定选择区域的位图,并且可以在回放的过程中对比这块窗口区域,这相当于提供了一个自动“目测”应用程序在实际屏幕显示时某个部分的方法。

\

我们可以点击Play按钮来运行我们的测试。过程中FlexMonkey回放了每一个在联系人管理应用程序中记录的操作,而应用程序的响应方式与手工操作键盘鼠标时完全一样。我们的简单测试运行结果如下:

\

45a937f9965de578ed9693d8c440b19d.jpg

\

通过这种方式使用FlexMonkey,我们可以交互性地创建和维护多种多样的,复杂的,可以包含任意数量测试用例和测试的套件。

\

使用ActionScript生成测试

\

除了交互性的创建和与运行测试外,我们还可以使用 FlexMonkey API 编程指定与xUnit框架如Fluint(http://fluint.googlecode.com)和FlexUnit 4(http://opensource.adobe.com/wiki/display/flexunit/FlexUnit)一起运行的测试。

\

尽管可以使用FlexMonkey API完全地从头开始创建测试,然而我们其实使用FlexMonkey控制台来直接从以前录制的测试场景中创建基于ActionScript的测试。选择 “生成 AS3”菜单选项来为每一个套件和测试用例生成ActionScript类。每一个独立的测试都会导出成它对应的测试用例类中的方法。下面是我们的简单示 例所生成的测试用例类。

\
\package testSuites.MonkeyContactsSuite.tests {\    import com.gorillalogic.flexmonkey.events.MonkeyCommandRunnerEvent;\    import com.gorillalogic.flexmonkey.core.MonkeyTest;\    import com.gorillalogic.flexmonkey.monkeyCommands.*;\    import com.gorillalogic.flexmonkey.application.VOs.AttributeVO;\    import com.gorillalogic.flexmonkey.flexunit.tests.MonkeyFlexUnitTestCase;\\    import mx.collections.ArrayCollection;\\    import flash.events.IEventDispatcher;\\    public class MonkeyContactsCase extends MonkeyFlexUnitTestCase{\\tpublic function MonkeyContactsCase(){\\t    super();\\t}\\\tprivate var mtTestAddNewContact:MonkeyTest = new MonkeyTest(null,\'TestAddNewContact', null, 500,\\t    new ArrayCollection([\\t\tnew UIEventMonkeyCommand('Input', 'inName', 'automationName', ['Fred']),\\t\tnew UIEventMonkeyCommand('Input', 'inPhone', 'automationName', ['555 555 1212']),\\t\tnew UIEventMonkeyCommand('Click', 'Add', 'automationName', ['0'])\\t\t]));\\\tprivate var mtTestAddNewContactTimeout:int = 8500;\\\t[Test]\\tpublic function TestAddNewContact():void{\\t    // startTest(\u0026lt;MonkeyTest\u0026gt;, \u0026lt;Complete method\u0026gt;, \u0026lt;Async timeout value\u0026gt;,\\u0026lt;Timeout method\u0026gt;)\\t     startTest(mtTestAddNewContact, TestAddNewContactComplete,\mtTestIA1TimeoutTime, defaultTimeoutHandler);\\t}\\\tpublic function TestAddNewContactComplete(event:MonkeyCommandRunnerEvent, passThroughData:Object):void{\\t     checkCommandResults(mtTestAddNewContact);\\t}\    }\}
\

测试中的每一个操作都生成出了一个UIEventMonkeyCommand。每一个命令都指定一个操作,属性/值对用以标识该操作以及操作相关参数所对应的目标组件。(所有可用的操作都在http://code.google.com/p/flexmonkey/wiki/FlexMonkeyCommand有 记录。)在这个例子中,每一个UIComponent都使用了automationName 属性来标识,但正如上面提到的,我们可以使用任意的属性值对来替代。我们可以很轻松的修改这些脚本而无须重新录制。例如,我们可以通过将下述命令加入到数 组中来实现在联系人管理中的ComboBox下选择电话类型为\"Mobile\"。

\
\new UIEventMonkeyCommand('Select', 'inType', 'id', ['Mobile'])
\

我们可以尝试用编程的方式向我们的管理程序中加入1000个联系人。例如,下面的几行代码相当于不断地输入一个唯一的联系人姓名并点击add按钮:

\
\for (var i:int=0; i\u0026lt;1000; i++)\    { mtTestAddNewContact.addItem(new UIEventMonkeyCommand('Input', 'inName', 'automationName', ['Contact' + i]));\    mtTestAddNewContact.addItem(new UIEventMonkeyCommand('Click', 'Add', 'automationName', ['0']));\}
\

对于每一个生成的测试方法,都会有一个对应的Complete方法。这个Complete方法会在测试方法结束后被调用。我们可以在这个方法中附加一些断言来测试其他的属性。例如,我们可以检查脚本完成后列表中第一个联系人是不是\"Fred\"。

\
\public function TestAddNewContactComplete(event:MonkeyCommandRunnerEvent, passThroughData:Object):void{\    var grid:DataGrid = MonkeyUtils.findComponentWith(\"grid\
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值