之前我介紹過doh用於UI單元測試,這篇文章介紹如何使用doh robot作介面自動化測試。
按照之前的介紹,讀者會發現要使用doh robot必須作如下兩件事情
1)編寫測試頁面,在頁面中寫入doh的測試代碼
2)上面的測試所有的頁面都是停留在當前頁面,沒有發生頁面提交的動作
那麼能不能在利用doh robot的介面動作類比來測試一個應用呢?答案是肯定的
doh robot停工如下兩個API來實現介面的自動化測試
initRobot: function(/*String*/ url){<br /> // summary:<br /> // Opens the application at the specified URL for testing, redirecting dojo to point to the application environment instead of the test environment.<br /> //<br /> // url:<br /> // URL to open. Any of the test's dojo.doc calls (e.g. dojo.byId()), and any dijit.registry calls (e.g. dijit.byId()) will point to elements and widgets inside this application.<br /> //<br />}<br />
waitForPageToLoad: function(/*Function*/ submitActions){<br /> // summary:<br /> // Notifies DOH that the doh.robot is about to make a page change in the application it is driving,<br /> // returning a doh.Deferred object the user should return in their runTest function as part of a DOH test.<br /> //<br /> // description:<br /> // Notifies DOH that the doh.robot is about to make a page change in the application it is driving,<br /> // returning a doh.Deferred object the user should return in their runTest function as part of a DOH test.<br /> // Example:<br /> // runTest:function(){<br /> // return waitForPageToLoad(function(){ doh.robot.keyPress(dojo.keys.ENTER, 500); });<br /> // }<br /> //<br /> // submitActions:<br /> // The doh.robot will execute the actions the test passes into the submitActions argument (like clicking the submit button),<br /> // expecting these actions to create a page change (like a form submit).<br /> // After these actions execute and the resulting page loads, the next test will start.<br /> //<br />}<br />
第一個API用於將應用中的串連加入到測試頁面,請看下面的代碼
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"<br /> "http://www.w3.org/TR/html4/strict.dtd"><br /><html><br /> <head><br /> <title>doh.robot Spinner Test</title><br /> <mce:style><!--<br /> @import "../../../../util/doh/robot/robot.css";</p><p>--></mce:style><mce:style mce_bogus="1"><!--<br /> @import "../../../../util/doh/robot/robot.css";</p><p>--></mce:style><mce:style mce_bogus="1" mce_bogus="1"><!--<br /> @import "../../../../util/doh/robot/robot.css";</p><p>--></mce:style><style mce_bogus="1" mce_bogus="1" mce_bogus="1"> @import "../../../../util/doh/robot/robot.css";<br /> </style><br /> <!-- required: dojo.js --><br /> <mce:script type="text/javascript" src="../../../../dojo/dojo.js" mce_src="dojo/dojo.js"<br /> djConfig="isDebug: true, parseOnLoad: true"></mce:script><br /> <mce:script type="text/javascript"><!--<br /> dojo.require("dijit.dijit"); // optimize: load dijit layer<br /> dojo.require("dijit.robotx"); // load the robot<br /> dojo.addOnLoad(function(){<br /> // declare variables but do not assign them values<br /> var spin1;<br /> var spin2;<br /> var spin3;<br /> var safeClick;<br /> var delta=1; // redefine with doh.robot.mouseWheelSize when it is available<br /> // the initRobot call goes here<br /> doh.robot.initRobot('../test_Spinner.html');<br /> doh.register("setUp",{<br /> name: "setUp",<br /> timeout: 15000,<br /> setUp:function(){<br /> // assign variables HERE<br /> spin1=dijit.byId('integerspinner1');<br /> spin2=dijit.byId('integerspinner2');<br /> spin3=dijit.byId('realspinner1');<br /> safeClick=dojo.byId('form1');<br /> },<br /> runTest: function(){<br /> // assert onChange not fired<br /> doh.is("not fired yet!",dojo.byId('oc1').value);<br /> doh.is(1,spin1.smallDelta);<br /> var s=": 900/n"<br /> +"integerspinner1: 900/n"<br /> +": not fired yet!/n"<br /> +": 1,000/n"<br /> +"integerspinner2: 1000/n"<br /> +": /n"<br /> +"integertextbox3: NaN/n"<br /> +": 1.0/n"<br /> +"realspinner1: 1/n";<br /> doh.is(s, dojo.doc.displayData().replace(/[a-zA-Z0-9_]*_displayed_/g, ""));<br /> }<br /> });<br /> doh.register("arrowButton",{<br /> name: "spinner1_invalid",<br /> timeout: 15000,<br /> runTest: function(){<br /> // assert invalid works<br /> var d=new doh.Deferred();<br /> doh.robot.mouseMoveAt(spin1.focusNode,500);<br /> doh.robot.mouseClick({left:true},500);<br /> doh.robot.sequence(function(){<br /> spin1.focusNode.value="";<br /> },500);<br /> doh.robot.typeKeys("0.5",500,300);<br /> doh.robot.sequence(function(){<br /> try{<br /> doh.is(false,spin1.isValid());<br /> d.callback(true);<br /> }catch(e){<br /> d.errback(e);<br /> }<br /> },500);<br /> return d;<br /> },<br /> tearDown:function(){<br /> spin1.attr('value',1);<br /> }<br /> });<br /> // ... some more tests<br /> // all tests registered; notify DOH<br /> doh.run();<br /> });</p><p>// --></mce:script><br /> </head>
通過上面的代碼,可以看出通過doh robot.initRobot,可以將外部的頁面引入doh測試架構。
如果我們觀察一下測試頁,可以發現其實現的時候,是用一個IFRANE將頁面框起來。
雖然有了IFRAME, dojo.doc指向的是你頁面的document,dojo.byId()可直接根據你頁面元素的Id獲得頁面中的控制項,如果你的項目是dojo項目,可以使用dijit.byId獲得widget對象。不過document,以及window對象指向的不是應用中頁面,而是測試代碼所在頁面。
waitForPageToLoad的範例例代碼如下,也比較容易讓人明白
doh.register('user_story1',{<br /> name: 'login_pagechange',<br /> timeout: 60000,<br /> runTest: function(){<br /> return doh.robot.waitForPageToLoad(function(){<br /> // click login<br /> doh.robot.mouseMoveAt(function(){ return dojo.doc.getElementsByTagName('input')[2]; }, 1623, 801);<br /> doh.robot.mouseClick({left:true, middle:false, right:false}, 992);<br /> });<br /> }<br /> });<br />
最後說一下doh測試結果獲得的介面
首先你的測試要納入整個doh的測試架構,包括要定義module.js以及測試套檔案
再次可以修改runner.html中的代碼,增加如下代碼
doh._onEnd = function()<br />{<br />//這裡加入你的處理<br />}
doh對象存在如下屬性,可以方便的獲得測試結果
_testCount,_errorCount,_failureCount