高效自动化 JavaScript 代码单元测试

简介: 能在一个浏览器上运行的 JavaScript 并不一定能在其他浏览器上运行。如果没有对代码进行单元测试,那么在决定升级或支持新浏览器的时候,组织就需要花钱测试或重新测试 Web 应用程序。在本文中,了解 JavaScript 单元测试如何帮助您降低测试成本,轻松支持更多浏览器。
  一个损坏的 JavaScript 代码示例
   Web 应用程序面临的一个最大挑战是支持不同版本的 Web 浏览器。能在 Safari 上运行的 JavaScript 代码不一定能在 Windows® Internet Explorer (IE)、Firefox 或 Google Chrome 上运行。这个挑战的根源是呈现层中的 JavaScript 代码从一开始就没有进行测试。如果没有对代码进行单元测试,那么在升级或支持新浏览器后,组织可能需要花钱反复测试 Web 应用程序。本文将展示如何通过高效的 JavaScript 代码单元测试降低测试成本。
  一个常见用例是登录表单 JavaScript 验证。考虑 清单 1(登录表单) 中的表单。
      登陆表单代码

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<FORM>

    <table>

        <tr>

            <td>Username</td>

            <td><input type="text" id="username"/></td>

            <td><span id="usernameMessage"></span></td>

        </tr>

        <tr>

            <td>Password</td>

            <td><input type="password" id="password"/></td>

            <td><span id="passwordMessage"></span></td>

        </tr>   

        <tr>

            <td><input type="button" onclick="new appnamespace.

            ApplicationUtil().validateLoginForm()" value="Submit"/></td>

        </tr>

    </table>

</FORM>

 

  这个表单很简单,仅包含用户名和密码字段。单击提交按钮时,将通过 ApplicationUtil 执行一个特定的表单验证。以下是负责验证 HTML 表单的 JavaScript 对象。清单 2 显示了 ApplicationUtil 对象的代码。
     损坏的 ApplicationUtil 对象代码

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

appnamespace = {};

     

appnamespace.ApplicationUtil = function() {};

     

appnamespace.ApplicationUtil.prototype.validateLoginForm =  function(){

    var error = true;

    document.getElementById("usernameMessage").innerText = "";

    document.getElementById("passwordMessage").innerText = "";   

     

    if (!document.getElementById("username").value) {

        document.getElementById("usernameMessage").innerText =

        "This field is required";

        error = false;

    }

         

    if (!document.getElementById("password").value) {

        document.getElementById("passwordMessage").innerText =

        "This field is required";

        error = false;

    }       

     

    return error;       

};

 

  在清单 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 的架构。

  
  ▲JsTestDriver架构
  jsTestDriver 是开源项目
   jsTestDriver 是 Apache 2.0 许可 下的一个开源项目,托管在 Google Code 上,后者是一个类似于 SourceForge 的项目存储库。只要使用 Open Source Initiative 批准的 许可,开发人员就能在这个存储库中创建和管理公共项目。
  还有许多其他 JavaScript 单元测试工具,请参见下面的 参考资料 部分中的其他工具,比如 Dojo Objective Harness (DOH)。
   捕获不同的浏览器之后,服务器会负责将 JavaScript 测试用例运行程序代码加载到浏览器中。可以通过命令行捕获浏览器,也可以通过将浏览器指向服务器 URL 来捕获浏览器。一旦捕获到浏览器,该浏览器就被称为从属浏览器。服务器可以加载 JavaScript 代码,在每个浏览器上执行测试用例,然后将结果返回给客户端。
  客户端(命令行)需要以下两个主要项目:
  JavaScript 文件,即源文件和测试文件
  配置文件,用于组织源文件和测试文件的加载
  这个架构比较灵活,允许单个服务器从网络中的其他机器捕获任意数量的浏览器。例如,如果您的代码在 Linux 上运行但您想针对另一个 Windows 机器上的 Microsoft Internet Explorer 运行您的测试用例,那么这个架构很有用。
  要使用 JsTestDriver 库,请先下载最新版的 JsTestDriver 1.3.2。
  编写单元测试代码
  现在开始编写 JavaScript 测试用例。为简单起见,我将测试以下用例:
  用户名和密码字段均为空。
  用户名为空,密码不为空。
  用户名不为空,密码为空。
  清单 3 显示了表示 TestCase 对象的 ApplicationUtilTest 对象的部分代码。
      ApplicationUtilTest 对象代码的一部分

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

ApplicationUtilTest = TestCase("ApplicationUtilTest");

     

ApplicationUtilTest.prototype.setUp = function () {

/*:DOC += <FORM action=""><table><tr><td>Username</td><td>

<input type="text" id="username"/></td><td><span id="usernameMessage">

</span></td></tr><tr><td>Password</td><td>

<input type="password" id="password"/></td><td><span id="passwordMessage"

></span></td></tr></table></FORM>*/

};

     

ApplicationUtilTest.prototype.testValidateLoginFormBothEmpty = function () {

    var applicationUtil = new appnamespace.ApplicationUtil();

         

    /* Simulate empty user name and password */

    document.getElementById("username").value = "";

    document.getElementById("password").value = "";   

         

    applicationUtil.validateLoginForm();

         

    assertEquals("Username is not validated correctly!", "This field is required",

    document.getElementById("usernameMessage").innerHTML);

    assertEquals("Password is not validated correctly!", "This field is required",

    document.getElementById("passwordMessage").innerHTML);   

};