qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          如何進行高效JavaScript單元測試

          如何進行高效JavaScript單元測試

           導讀:能在一個瀏覽器上運行的JavaScript并不一定能在其他瀏覽器上運行。如果沒有對代碼進行單元測試,那么在決定升級或支持新瀏覽器的時候,組織就需要花錢測試或重新測試Web應用程序。在本文中,了解JavaScript單元測試如何幫助您降低測試成本,輕松支持更多瀏覽器。

            一個損壞的JavaScript代碼示例

            Web應用程序面臨的一個最大挑戰是支持不同版本的Web瀏覽器。能在Safari上運行的JavaScript代碼不一定能在Windows? Internet Explorer (IE)、Firefox或Google Chrome上運行。這個挑戰的根源是呈現層中的JavaScript代碼從一開始就沒有進行測試。如果沒有對代碼進行單元測試,那么在升級或支持新瀏覽器后,組織可能需要花錢反復測試Web應用程序。本文將展示如何通過高效的JavaScript代碼單元測試降低測試成本。

            一個常見用例是登錄表單JavaScript驗證。考慮清單1中的表單。

            清單 1.登錄表單

        1. <FORM> 
        2.     <table> 
        3.         <tr> 
        4.             <td>Username</td> 
        5.             <td><input type="text" id="username"/></td> 
        6.             <td><span id="usernameMessage"></span></td> 
        7.         </tr> 
        8.         <tr> 
        9.             <td>Password</td> 
        10.             <td><input type="password" id="password"/></td> 
        11.             <td><span id="passwordMessage"></span></td> 
        12.         </tr>     
        13.         <tr> 
        14.             <td><input type="button" onclick="new appnamespace.  
        15.             ApplicationUtil().validateLoginForm()" value="Submit"/></td> 
        16.         </tr> 
        17.     </table> 
        18. </FORM>
        19.   這個表單很簡單,僅包含用戶名和密碼字段。單擊提交按鈕時,將通過ApplicationUtil執行一個特定的表單驗證。以下是負責驗證HTML表單的JavaScript對象。清單2顯示了ApplicationUtil對象的代碼。

            清單 2.損壞的ApplicationUtil對象代

        20. appnamespace = {};  
        21. appnamespace.ApplicationUtil = function() {};  
        22. appnamespace.ApplicationUtil.prototype.validateLoginForm =  function(){  
        23.     var error = true;  
        24.     document.getElementById("usernameMessage").innerText = "";  
        25.     document.getElementById("passwordMessage").innerText = "";    
        26.     if (!document.getElementById("username").value) {  
        27.         document.getElementById("usernameMessage").innerText =   
        28.         "This field is required";  
        29.         error = false;  
        30.     }  
        31.       
        32.     if (!document.getElementById("password").value) {  
        33.         document.getElementById("passwordMessage").innerText =   
        34.         "This field is required";  
        35.         error = false;  
        36.     }         
        37.     return error;         
        38. };
        39.   在清單 2中,ApplicationUtil對象提供一個簡單驗證:用戶名和密碼字段都已填充。如果某個字段為空,就會顯示一條錯誤消息:This field is required。

            上面的代碼能夠在Internet Explorer 8和Safari 5.1上工作,但無法在 Firefox 3.6 上工作,原因是Firefox不支持innerText屬性。通常,(上述代碼和其他類似JavaScript代碼中的)主要問題是不容易發現編寫的JavaScript代碼是不是跨瀏覽器兼容的。

            這個問題的一個解決方案是進行自動化單元測試,檢查代碼是不是跨瀏覽器兼容。

            JsTestDriver

            JsTestDriver library是最好的JavaScript單元測試框架之一,它為JavaScript代碼提供了跨瀏覽器測試。圖 1展示了JsTestDriver的架構。

            圖 1.JsTestDriver架構

            捕獲不同的瀏覽器之后,服務器會負責將JavaScript測試用例運行程序代碼加載到瀏覽器中。可以通過命令行捕獲瀏覽器,也可以通過將瀏覽器指向服務器URL來捕獲瀏覽器。一旦捕獲到瀏覽器,該瀏覽器就被稱為從屬瀏覽器。服務器可以加載JavaScript代碼,在每個瀏覽器上執行測試用例,然后將結果返回給客戶端。

            客戶端(命令行)需要以下兩個主要項目:

            ● JavaScript文件,即源文件和測試文件
            ● 配置文件,用于組織源文件和測試文件的加載

            這個架構比較靈活,允許單個服務器從網絡中的其他機器捕獲任意數量的瀏覽器。例如,如果您的代碼在Linux上運行但您想針對另一個Windows機器上的Microsoft Internet Explorer運行您的測試用例,那么這個架構很有用。

            要使用JsTestDriver庫,請先下載最新版的JsTestDriver 1.3.2。

            jsTestDriver是開源項目

            jsTestDriver是Apache 2.0 許可下的一個開源項目,托管在Google Code上,后者是一個類似于SourceForge的項目存儲庫。只要使用Open Source Initiative批準的許可,開發人員就能在這個存儲庫中創建和管理公共項目。

            還有許多其他JavaScript單元測試工具,請參見下面的參考資料部分中的其他工具,比如Dojo Objective Harness (DOH)。

            編寫單元測試代碼

            現在開始編寫JavaScript測試用例。為簡單起見,我將測試以下用例:

            ● 用戶名和密碼字段均為空。
            ● 用戶名為空,密碼不為空。
            ● 用戶名不為空,密碼為空。

            清單 3顯示了表示TestCase對象的ApplicationUtilTest對象的部分代碼。

            清單 3.ApplicationUtilTest 對象代碼的一部分

        40. ApplicationUtilTest = TestCase("ApplicationUtilTest");  
        41.  
        42. ApplicationUtilTest.prototype.setUp = function () {  
        43. /*:DOC += <FORM action=""><table><tr><td>Username</td><td> 
        44. <input type="text" id="username"/></td><td><span id="usernameMessage"> 
        45. </span></td></tr><tr><td>Password</td><td> 
        46. <input type="password" id="password"/></td><td><span id="passwordMessage" 
        47. ></span></td></tr></table></FORM>*/  
        48. };  
        49.  
        50. ApplicationUtilTest.prototype.testValidateLoginFormBothEmpty = function () {  
        51.     var applicationUtil = new appnamespace.ApplicationUtil();  
        52.       
        53.     /* Simulate empty user name and password */  
        54.     document.getElementById("username").value = "";  
        55.     document.getElementById("password").value = "";   
        56.       
        57.     applicationUtil.validateLoginForm();  
        58.       
        59.     assertEquals("Username is not validated correctly!", "This field is required",   
        60.     document.getElementById("usernameMessage").innerHTML);  
        61.     assertEquals("Password is not validated correctly!", "This field is required",   
        62.     document.getElementById("passwordMessage").innerHTML);    
        63. };


        64.  ApplicationUtilTest對象通過JsTestDriver TestCase對象創建。如果您熟悉JUnit框架,那么您肯定熟悉setUp和testXXX方法。setUp方法用于初始化測試用例。對于本例,我使用該方法來聲明一個HTML片段,該片段將用于其他測試用例方法。

            DOC注釋是一個JsTestDriver慣用語,可以用于輕松聲明一個HTML片段。

            在testValidateLoginFormBothEmpty方法中,創建了一個ApplicationUtil對象,并在測試用例方法中使用該對象。然后,代碼通過檢索用戶名和密碼的DOM元素并將它們的值設置為空值來模擬輸入空用戶名和密碼。可以調用validateLoginForm方法來執行實際表單驗證。最后,將調用assertEquals來確保usernameMessage 和 passwordMessage span元素中的消息是正確的,即:This field is required。

            在JsTestDriver中,可以使用以下構件:

            ● fail ("msg"):表明測試一定會失敗,消息參數將顯示為一條錯誤消息。
            ● assertTrue ("msg", actual):斷定實際參數正確。否則,消息參數將顯示為一條錯誤消息。
            ● assertFalse ("msg", actual):斷定實際參數錯誤。否則,消息參數將顯示為一條錯誤消息。
            ● assertSame ("msg", expected, actual):斷定實際參數與預期參數相同。否則,消息參數將顯示為一條錯誤消息。
            ● assertNotSame ("msg", expected, actual):斷定實際參數與預期參數不相同。否則,消息參數將顯示為一條錯誤消息。
            ● assertNull ("msg", actual):斷定參數為空。否則,消息參數將顯示為一條錯誤消息。
            ● assertNotNull ("msg", actual):斷定實際參數不為空。否則,消息參數將顯示為一條錯誤消息。

            其他方法的代碼包含其他測試用例。清單 4 顯示了測試用例對象的完整代碼。

            清單 4. ApplicationUtil 對象完整代碼

        65. ApplicationUtilTest = TestCase("ApplicationUtilTest");  
        66.  
        67. ApplicationUtilTest.prototype.setUp = function () {  
        68. /*:DOC += <FORM action=""><table><tr><td>Username</td><td> 
        69. <input type="text" id="username"/></td><td><span id="usernameMessage"> 
        70. </span></td></tr><tr><td>Password</td><td> 
        71. <input type="password" id="password"/></td><td><span id="passwordMessage" 
        72. ></span></td></tr></table></FORM>*/  
        73. };  
        74.  
        75. ApplicationUtilTest.prototype.testValidateLoginFormBothEmpty = function () {  
        76.     var applicationUtil = new appnamespace.ApplicationUtil();  
        77.       
        78.     /* Simulate empty user name and password */  
        79.     document.getElementById("username").value = "";  
        80.     document.getElementById("password").value = "";   
        81.       
        82.     applicationUtil.validateLoginForm();  
        83.       
        84.     assertEquals("Username is not validated correctly!", "This field is required",   
        85.     document.getElementById("usernameMessage").innerHTML);  
        86.     assertEquals("Password is not validated correctly!", "This field is required",   
        87.     document.getElementById("passwordMessage").innerHTML);    
        88. };  
        89.  
        90. ApplicationUtilTest.prototype.testValidateLoginFormWithEmptyUserName = function () {  
        91.     var applicationUtil = new appnamespace.ApplicationUtil();  
        92.       
        93.     /* Simulate empty user name and password */  
        94.     document.getElementById("username").value = "";  
        95.     document.getElementById("password").value = "anyPassword";    
        96.       
        97.     applicationUtil.validateLoginForm();  
        98.       
        99.     assertEquals("Username is not validated correctly!",   
        100.     "This field is required", document.getElementById("usernameMessage").innerHTML);  
        101.     assertEquals("Password is not validated correctly!",   
        102.     "", document.getElementById("passwordMessage").innerHTML);    
        103. };  
        104.  
        105. ApplicationUtilTest.prototype.testValidateLoginFormWithEmptyPassword = function () {  
        106.     var applicationUtil = new appnamespace.ApplicationUtil();  
        107.       
        108.     document.getElementById("username").value = "anyUserName";  
        109.     document.getElementById("password").value = "";   
        110.       
        111.     applicationUtil.validateLoginForm();  
        112.       
        113.     assertEquals("Username is not validated correctly!",   
        114.     "", document.getElementById("usernameMessage").innerHTML);  
        115.     assertEquals("Password is not validated correctly!",   
        116.     "This field is required", document.getElementById("passwordMessage").  
        117.     innerHTML);   
        118. };

        119.  配置用于測試的不同瀏覽器

            測試JavaScript代碼的一個推薦實踐是將JavaScript源代碼和測試代碼放置在不同的文件夾中。對于圖 2中的示例,我將JavaScript源文件夾命名為“js-src”,將JavaScript測試文件夾命名為“js-test”,它們都位于“js”父文件夾下。

            圖 2. JavaScript測試文件夾結構

            組織好源和測試文件夾后,必須提供配置文件。默認情況下,JsTestDriver運行程序會尋找名為jsTestDriver.conf的配置文件。您可以從命令行更改配置文件名稱。清單 5顯示了JsTestDriver配置文件的內容。

            清單 5.JsTestDriver配置文件內容

        120. server: http://localhost:9876  
        121.  
        122. load:  
        123.   - js-src/*.js  
        124.   - js-test/*.js
        125.   配置文件采用YAML格式。server指令指定測試服務器的地址,load指令指出了將哪些JavaScript文件加載到瀏覽器中以及加載它們的順序。

            現在,我們將在IE、Firefox和Safari瀏覽器上運行測試用例類。

            要運行測試用例類,需要啟動服務器。您可以使用以下命令行啟動JsTestDriver服務器:

        126. java -jar JsTestDriver-1.3.2.jar --port 9876 --browser "[Firefox Path]",  
        127.           "[IE Path]","[Safari Path]"
        128.   使用這個命令行,服務器將以Port 9876啟動,捕獲您的機器上的Firefox、IE和Safari瀏覽器。

            啟動并捕獲瀏覽器后,可以通過以下命令行運行測試用例類:

          java -jar JsTestDriver-1.3.2.jar --tests all

           運行命令后,您將看到第一輪結果,如清單 6 所示。

            清單 6.第一輪結果

        129. Total 9 tests (Passed: 6; Fails: 3; Errors: 0) (16.00 ms)  
        130.   Firefox 3.6.18 Windows: Run 3 tests (Passed: 0; Fails: 3; Errors 0) (8.00 ms)  
        131.     ApplicationUtilTest.testValidateLoginFormBothEmpty failed (3.00 ms):   
        132.     AssertError: Username is not validated correctly! expected "This field   
        133.     is required" but was "" Error("Username is not validated correctly!   
        134.     expected \"This field is required\" but was \"\"")@:0()@http://localhost  
        135.     :9876/test/js-test/TestApplicationUtil.js:16  
        136.  
        137.     ApplicationUtilTest.testValidateLoginFormWithEmptyUserName failed (3.00 ms):   
        138.     AssertError: Username is not validated correctly! expected "This field is   
        139.     required" but was "" Error("Username is not validated correctly! expected   
        140.     \"This field is required\" but was \"\"")@:0()@http://localhost:9876/test  
        141.     /js-test/TestApplicationUtil.js:29  
        142.  
        143.     ApplicationUtilTest.testValidateLoginFormWithEmptyPassword failed (2.00 ms):   
        144.     AssertError: Password is not validated correctly! expected "This field is   
        145.     required" but was "" Error("Password is not validated correctly! expected   
        146.     \"This field is required\" but was \"\"")@:0()@http://localhost:9876/test/  
        147.     js-test/TestApplicationUtil.js:42  
        148.       
        149.   Safari 534.50 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (2.00 ms)  
        150.   Microsoft Internet Explorer 8.0 Windows: Run 3 tests (Passed: 3; Fails: 0;   
        151.   Errors 0) (16.00 ms)  
        152. Tests failed: Tests failed. See log for details.
        153.   注意,在清單 6 中,主要問題出在 Firefox 上。測試在 Internet Explorer 和 Safari 上均可順利運行。

            修復JavaScript代碼并重新運行測試用例

            我們來修復損壞的JavaScript代碼。我們將使用innerHTML替代innerText。清單 7顯示了修復后的ApplicationUtil對象代碼。

            清單 7.修復后的ApplicationUtil對象代碼

        154. appnamespace = {};  
        155.  
        156. appnamespace.ApplicationUtil = function() {};  
        157.  
        158. appnamespace.ApplicationUtil.prototype.validateLoginForm =  function(){  
        159.     var error = true;  
        160.     document.getElementById("usernameMessage").innerHTML = "";  
        161.     document.getElementById("passwordMessage").innerHTML = "";    
        162.  
        163.     if (!document.getElementById("username").value) {  
        164.         document.getElementById("usernameMessage").innerHTML =   
        165.         "This field is required";  
        166.         error = false;  
        167.     }  
        168.       
        169.     if (!document.getElementById("password").value) {  
        170.         document.getElementById("passwordMessage").innerHTML =   
        171.         "This field is required";  
        172.         error = false;  
        173.     }         
        174.  
        175.     return error;         
        176. };
        177.   使用 --test all 命令行參數重新運行測試用例對象。清單 8 顯示了第二輪運行結果。

            清單 8.第二輪運行結果

        178. Total 9 tests (Passed: 9; Fails: 0; Errors: 0) (9.00 ms)  
        179.   Firefox 3.6.18 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (9.00 ms)  
        180.   Safari 534.50 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)  
        181.   Microsoft Internet Explorer 8.0 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0)   
        182.   (0.00 ms)
        183.   如清單 8所示,JavaScript代碼現在在IE、Firefox和Safari上都能正常運行。

            結束語

            在本文中,您了解了如何使用一個最強大的JavaScript單元測試工具(JsTestDriver)在不同的瀏覽器上測試JavaScript應用程序代碼。還了解了什么是JsTestDriver,如何配置它,以及如何在Web應用程序中使用它來確保應用程序的JavaScript代碼的質量和可靠性。

          posted on 2011-12-08 14:47 順其自然EVO 閱讀(209) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 仪征市| 威信县| 磐安县| 垫江县| 独山县| 阳江市| 神池县| 永宁县| 武隆县| 兴隆县| 琼结县| 华安县| 贵港市| 中宁县| 松桃| 朝阳县| 奉新县| 从化市| 荣昌县| 黔西县| 普安县| 三亚市| 屯昌县| 寿宁县| 阳泉市| 汶上县| 通辽市| 霍林郭勒市| 鹤峰县| 新泰市| 侯马市| 泾阳县| 昆山市| 和田县| 南康市| 沅江市| 金沙县| 白水县| 伊宁市| 新竹县| 镇赉县|