您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
高效的JavaScript单元测试
 
来源:伯乐在线 发布于 2015-8-26
   次浏览      
 

简介: 能在一个浏览器上运行的 JavaScript 并不一定能在其他浏览器上运行。如果没有对代码进行单元测试,那么在决定升级或支持新浏览器的时候,公司就需要花钱测试或重新测试 Web 应用程序。在本文中,了解 JavaScript 单元测试如何帮助您降低测试成本,轻松支持更多浏览器。

一个损坏的 JavaScript 代码示例

Web 应用程序面临的一个最大挑战是支持不同版本的 Web 浏览器。能在 Safari 上运行的 JavaScript 代码不一定能在 Windows? Internet Explorer (IE)、Firefox 或 Google Chrome 上运行。这个挑战的根源是呈现层中的 JavaScript 代码从一开始就没有进行测试。如果没有对代码进行单元测试,那么在升级或支持新浏览器后,组织可能需要花钱反复测试 Web 应用程序。本文将展示如何通过高效的 JavaScript 代码单元测试降低测试成本。

一个常见用例是登录表单 JavaScript 验证。考虑 清单 1 中的表单。

清单 1. 登录表单

<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 对象的代码。

<strong>清单 2. 损坏的 ApplicationUtil 对象代码</strong>

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 架构 高效的JavaScript单元测试

捕获不同的浏览器之后,服务器会负责将 JavaScript 测试用例运行程序代码加载到浏览器中。可以通过命令行捕获浏览器,也可以通过将浏览器指向服务器 URL 来捕获浏览器。一旦捕获到浏览器,该浏览器就被称为从属浏览器。服务器可以加载 JavaScript 代码,在每个浏览器上执行测试用例,然后将结果返回给客户端。

客户端(命令行)需要以下两个主要项目:

1.JavaScript 文件,即源文件和测试文件

2.配置文件,用于组织源文件和测试文件的加载

这个架构比较灵活,允许单个服务器从网络中的其他机器捕获任意数量的浏览器。例如,如果您的代码在 Linux 上运行但您想针对另一个 Windows 机器上的 Microsoft Internet Explorer 运行您的测试用例,那么这个架构很有用。

要使用 JsTestDriver 库,请先下载最新版的 JsTestDriver 1.3.2。

编写单元测试代码

现在开始编写 JavaScript 测试用例。为简单起见,我将测试以下用例:

用户名和密码字段均为空。

用户名为空,密码不为空。

用户名不为空,密码为空。

清单 3 显示了表示 TestCase 对象的 ApplicationUtilTest 对象的部分代码。

清单 3. ApplicationUtilTest 对象代码的一部分

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);
};

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 对象完整代码

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);
};

ApplicationUtilTest.prototype.testValidateLoginFormWithEmptyUserName = function () {
var applicationUtil = new appnamespace.ApplicationUtil();


/* Simulate empty user name and password */
document.getElementById("username").value = "";
document.getElementById("password").value = "anyPassword";

applicationUtil.validateLoginForm();

assertEquals("Username is not validated correctly!",
"This field is required", document.getElementById("usernameMessage").innerHTML);
assertEquals("Password is not validated correctly!",
"", document.getElementById("passwordMessage").innerHTML);
};

ApplicationUtilTest.prototype.testValidateLoginFormWithEmptyPassword = function () {
var applicationUtil = new appnamespace.ApplicationUtil();

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

applicationUtil.validateLoginForm();

assertEquals("Username is not validated correctly!",
"", document.getElementById("usernameMessage").innerHTML);
assertEquals("Password is not validated correctly!",
"This field is required", document.getElementById("passwordMessage").
innerHTML);
};

<strong>配置用于测试的不同浏览器</strong>

测试 JavaScript 代码的一个推荐实践是将 JavaScript 源代码和测试代码放置在不同的文件夹中。对于 图 2 中的示例,我将 JavaScript 源文件夹命名为 “js-src”,将 JavaScript 测试文件夹命名为 “js-test”,它们都位于 “js” 父文件夹下。

图 2. JavaScript 测试文件夹结构

组织好源和测试文件夹后,必须提供配置文件。默认情况下,JsTestDriver 运行程序会寻找名为 jsTestDriver.conf 的配置文件。您可以从命令行更改配置文件名称。清单 5 显示了 JsTestDriver 配置文件的内容。

清单 5. JsTestDriver 配置文件内容

server: http:
//localhost:9876

load:
- js-src/*.js
- js-test/*.js

配置文件采用 YAML 格式。server 指令指定测试服务器的地址,load 指令指出了将哪些 JavaScript 文件加载到浏览器中以及加载它们的顺序。

现在,我们将在 IE、Firefox 和 Safari 浏览器上运行测试用例类。

要运行测试用例类,需要启动服务器。您可以使用以下命令行启动 JsTestDriver 服务器:

java -jar JsTestDriver-1.3.2.jar --port 9876 --browser "[Firefox Path]",
"[IE Path]","[Safari Path]"

使用这个命令行,服务器将以 Port 9876 启动,捕获您的机器上的 Firefox、IE 和 Safari 浏览器。 启动并捕获浏览器后,可以通过以下命令行运行测试用例类:

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

运行命令后,您将看到第一轮结果,如 清单 6所示。

清单 6. 第一轮结果

Total 9 tests (Passed: 6; Fails: 3; Errors: 0) (16.00 ms)
Firefox 3.6.18 Windows: Run 3 tests (Passed: 0; Fails: 3; Errors 0) (8.00 ms)
ApplicationUtilTest.testValidateLoginFormBothEmpty failed (3.00 ms):
AssertError: Username is not validated correctly! expected "This field
is required" but was "" Error("Username is not validated correctly!
expected \"This field is required\" but was \"\"")@:0()@http:
//localhost
:9876/test/js-test/TestApplicationUtil.js:16

ApplicationUtilTest.testValidateLoginFormWithEmptyUserName failed (3.00 ms):
AssertError: Username is not validated correctly! expected "This field is
required" but was "" Error("Username is not validated correctly! expected
\"This field is required\" but was \"\"")@:0()@http:
//localhost:9876/test
/js-test/TestApplicationUtil.js:29

ApplicationUtilTest.testValidateLoginFormWithEmptyPassword failed (2.00 ms):
AssertError: Password is not validated correctly! expected "This field is
required" but was "" Error("Password is not validated correctly! expected
\"This field is required\" but was \"\"")@:0()@http:
//localhost:9876/test/
js-test/TestApplicationUtil.js:42

Safari 534.50 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (2.00 ms)
Microsoft Internet Explorer 8.0 Windows: Run 3 tests (Passed: 3; Fails: 0;
Errors 0) (16.00 ms)
Tests failed: Tests failed. See log for details.

注意,在清单 6 中,主要问题出在 Firefox 上。测试在 Internet Explorer 和 Safari 上均可顺利运行。 回页首 修复 JavaScript 代码并重新运行测试用例 我们来修复损坏的 JavaScript 代码。我们将使用 innerHTML 替代 innerText。清单 7 显示了修复后的 ApplicationUtil对象代码。

清单 7. 修复后的 ApplicationUtil 对象代码

appnamespace = {};

appnamespace.ApplicationUtil = function() {};

appnamespace.ApplicationUtil.prototype.validateLoginForm = function(){
var error = true;
document.getElementById("usernameMessage").innerHTML = "";
document.getElementById("passwordMessage").innerHTML = "";

if (!document.getElementById("username").value) {
document.getElementById("usernameMessage").innerHTML =
"This field is required";
error = false;
}

if (!document.getElementById("password").value) {
document.getElementById("passwordMessage").innerHTML =
"This field is required";
error = false;
}

return error;
};

使用 --test all 命令行参数重新运行测试用例对象。清单 8显示了第二轮运行结果。

清单 8. 第二轮运行结果

Total 9 tests (Passed: 9; Fails: 0; Errors: 0) (9.00 ms)
Firefox 3.6.18 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (9.00 ms)
Safari 534.50 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
Microsoft Internet Explorer 8.0 Windows: Run 3 tests (Passed: 3; Fails: 0; Errors 0)
(0.00 ms)

如清单 8 所示,JavaScript 代码现在在 IE、Firefox 和 Safari 上都能正常运行。

结束语

在本文中,您了解了如何使用一个最强大的 JavaScript 单元测试工具 (JsTestDriver) 在不同的浏览器上测试 JavaScript应用程序代码。还了解了什么是 JsTestDriver,如何配置它,以及如何在 Web 应用程序中使用它来确保应用程序的 JavaScript代码的质量和可靠性。

   
次浏览       
相关文章

微服务测试之单元测试
一篇图文带你了解白盒测试用例设计方法
全面的质量保障体系之回归测试策略
人工智能自动化测试探索
相关文档

自动化接口测试实践之路
jenkins持续集成测试
性能测试诊断分析与优化
性能测试实例
相关课程

持续集成测试最佳实践
自动化测试体系建设与最佳实践
测试架构的构建与应用实践
DevOps时代的测试技术与最佳实践
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

LoadRunner性能测试基础
软件测试结果分析和质量报告
面向对象软件测试技术研究
设计测试用例的四条原则
功能测试中故障模型的建立
性能测试综述
更多...   

性能测试方法与技术
测试过程与团队管理
LoadRunner进行性能测试
WEB应用的软件测试
手机软件测试
白盒测试方法与技术

某博彩行业 数据库自动化测试
IT服务商 Web安全测试
IT服务商 自动化测试框架
海航股份 单元测试、重构
测试需求分析与测试用例分析
互联网web测试方法与实践
基于Selenium的Web自动化测试
更多...