`
netcome
  • 浏览: 479446 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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


清单 2. 损坏的 ApplicationUtil 对象代码

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


图 1. JsTestDriver 架构

jsTestDriver 是开源项目

jsTestDriver 是 Apache 2.0 许可 下的一个开源项目,托管在 Google Code 上,后者是一个类似于 SourceForge 的项目存储库。只要使用 Open Source Initiative 批准的 许可 ,开发人员就能在这个存储库中创建和管理公共项目。

还有许多其他 JavaScript 单元测试工具,请参见下面的 参考资料 部分中的其他工具,比如 Dojo Objective Harness (DOH)。

捕获不同的浏览器之后,服务器会负责将 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 框架,那么您肯定熟悉 setUptestXXX 方法。setUp 方法用于初始化测试用例。对于本例,我使用该方法来声明一个 HTML 片段,该片段将用于其他测试用例方法。

DOC 注释是一个 JsTestDriver 惯用语,可以用于轻松声明一个 HTML 片段。

testValidateLoginFormBothEmpty 方法中,创建了一个 ApplicationUtil 对象,并在测试用例方法中使用该对象。然后,代码通过检索用户名和密码的 DOM 元素并将它们的值设置为空值来模拟输入空用户名和密码。可以调用 validateLoginForm 方法来执行实际表单验证。最后,将 调用 assertEquals 来确保 usernameMessagepasswordMessage 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);	
};

 


配置用于测试的不同浏览器

测试 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 代码的质量和可靠性。

 


下载

描述 名字 大小 下载方法
源代码 simple.zip 3.35MB HTTP

关于下载方法的信息

 

本文转载于developerWorks,原文在这里

分享到:
评论

相关推荐

    JSUnit Javascript单元测试

    JavaScript单元测试是软件开发过程中的一个关键环节,它允许开发者对代码的各个独立部分进行验证,确保它们在预期情况下能够正确工作。JSUnit是专为JavaScript设计的一个单元测试框架,它使得JavaScript应用程序的...

    JavaScript单元测试工具安装说明书

    JavaScript单元测试工具JS Test Driver是一种高效且方便的测试框架,它允许开发者在无需打开浏览器的情况下进行JavaScript代码的单元测试,类似于Java的单元测试方式。这一工具显著提升了开发效率,减少了对浏览器...

    多浏览器的单元测试工具 多浏览器集成的JavaScript单元测试工县 共28页.pdf

    **多浏览器的JavaScript单元测试工具概述** 在软件开发过程中,单元测试是确保代码质量的关键步骤。对于JavaScript,由于其在不同浏览器中可能存在兼容性问题,因此进行多浏览器的单元测试显得尤为重要。本文将探讨...

    JavaScript单元测试Jasmine源代码

    JavaScript单元测试是软件开发过程中的重要环节,它用于验证代码的各个独立部分(即单元)是否按预期工作。Jasmine是一款流行的JavaScript测试框架,尤其适用于前端开发者,它提供了丰富的断言库和易于理解的语法,...

    测试他们的脚本!一个让Javascript单元测试变得有趣的测试运行器。___下载.zip

    总的来说,Testem通过其强大的功能和用户友好的特性,使得JavaScript单元测试变得更加高效和愉快,是现代前端开发不可或缺的工具之一。无论你是个人开发者还是团队协作,Testem都能帮助你确保代码质量,提升开发效率...

    JavaScript对象封装与单元测试.pdf

    JavaScript对象封装与单元测试 JavaScript对象封装是指将JavaScript代码组织成一个对象的形式,以便于测试和维护。单元测试是软件测试的一种,目标是确保每个单元的正确性。在JavaScript开发中,单元测试是非常...

    Vue单元测试视频

    在前端开发领域,尤其是在使用Vue.js这样的现代JavaScript框架进行开发时,进行有效的单元测试显得尤为重要。 #### 二、Vue单元测试的意义 1. **提高代码质量**:通过编写测试用例,可以确保代码逻辑正确无误,...

    javascript 测试工具

    在JavaScript的世界里,有许多优秀的测试框架和库可供选择,其中JSUnit是一个早期的JavaScript单元测试框架。 **JSUnit简介** JSUnit是由Draney在2002年创建的,它是JavaScript的早期测试框架之一,主要用于Web应用...

    Javascript单元测试框架QUnitjs详细介绍

    QUnit 是一个专门用于 JavaScript 代码的单元测试框架,由 jQuery 团队成员创建,同时也是 jQuery 的官方测试工具。虽然最初与 jQuery 相关,但 QUnit 可以应用于任何普通的 JavaScript 代码,甚至支持在服务器端 ...

    jsunit单元测试技术讲解

    【JavaScript 单元测试技术详解】 单元测试是软件开发中不可或缺的一个环节,它专注于验证代码的各个独立组件是否...在实践中,单元测试应成为每个开发者日常工作中不可或缺的一部分,以实现高效、可靠的软件开发。

    高效的JavaScript代码单元测试方法

    高效的JavaScript代码单元测试方法!一个损坏的JavaScript代码示例Web应用程序面临的一个最大挑战是支持不同版本的Web浏览器。能在Safari上运行的JavaScript代码不一定能在WindowsInternetExplorer(IE)、Firefox或...

    Luna是一个简单现代的单元测试框架用于在浏览器或Nodejs中测试JavaScript

    Luna是一个专为JavaScript设计的轻量级且现代化的单元测试框架,它提供了在浏览器环境和Node.js环境中进行测试的强大功能。这个框架的诞生旨在简化测试流程,使得开发者能够更加专注于代码质量,而不再被复杂的测试...

    UNit_Test单元测试课件

    这些框架提供了丰富的断言库和方便的测试组织结构,使得编写和运行单元测试变得简单高效。 在学习和实践单元测试时,应注意以下几点: 1. 测试覆盖:确保测试覆盖了所有可能的输入情况,包括正常路径、边界条件和...

    第15章 单元测试和功能测试1

    单元测试和功能测试是软件开发中两种关键的自动化测试方法,尤其在面向对象编程和Web应用开发中起着至关重要的作用。它们有助于确保代码质量,减少错误,提高开发效率。 **单元测试**主要关注代码的单一组件或模块...

    软件测试-基于node.js开发的单元测试实例.zip

    在IT行业中,软件测试是确保产品质量的关键步骤,而单元测试是软件测试的一种基本类型。本教程将深入探讨如何使用Node.js进行单元测试的实践。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它以其非阻塞I/O...

    单元静态测试工具教学

    单元测试是对软件中的最小可测试单元,通常是函数、方法或类,进行独立验证的过程。它的目标是确保每个单元都能按照预期工作,以便在集成过程中减少错误和问题。而静态测试则是在不执行代码的情况下,通过分析代码...

    jasmine-node:javascript 单元测试

    ** Jasmine-Node:JavaScript 单元测试框架** Jasmine-Node 是一个用于 JavaScript 的单元测试框架,它将流行的 Jasmine 测试库扩展到了 Node.js 环境中。Jasmine 是一个行为驱动开发(BDD)的测试框架,它以其...

Global site tag (gtag.js) - Google Analytics