JavaScript测试调研
前言
与其他语言相似,JavaScript的测试也会包括代码审查、单元测试等内容。本文就JavaScript的测试调研了一些测试工具和测试框架。
相对于其他很多高级语言语言相比,JavaScript的单元测试可能相对来言麻烦点。当然就单元测试来讲,JavaScript单元测试也需要依赖于一些小的测试框架和测试组件来帮助我们完成真正的测试用例。
1 JsUnit
1.1 简介
JsUnit是JavaScript的开源单元测试框架。它受到JUnit的启发,并完全用JavaScript编写。这是以前流行的一个JavaScript的单元测试工具,可以和Maven以及Ant结合来完成一些持续集成的工作。
1.2 使用步骤初探
(1) 下载JsUnit,然后解压文件。下载地址:http://sourceforge.net/projects/jsunit/?source=navbar
(2) 使用浏览器打开解压目录下的testRunner.html文件。
(3) 准备测试用例,可以直接使用下载目录中的tests文件夹中的一个测试用例的page来做试验。
(4) 运行测试用例,将测试套件或者测试文件路径填入输入框中。点击运行即可,运行完后我们可以看到运行后的结果。
1.3 JsUnit测试用例的编写示例
(1) 一个简单的测试用例的编写
<html> <title>A unit test for drw.SystemUnderTest class</title> <head> <script type='text/javascript' src='../jsunit/app/jsUnitCore.js'></script> <link rel="stylesheet" type="text/css" href="../css/jsUnitStyle.css"> <script type='text/javascript' src='../app/system_under_test.js'></script> <script type='text/javascript'> function setUp(){ // perform fixture set up } function tearDown() { // clean up } function testOneThing(){ // instantiating a SystemUnderTest, a class in the drw namespace var sut = new drw.SystemUnderTest(); var thing = sut.oneThing(); assertEquals(1, thing); } function testAnotherThing(){ var sut = new drw.SystemUnderTest(); var thing = sut.anotherThing(); assertNotEquals(1, thing); } </script> </head> <body/> </html> |
以上为测试用例的编写的一个示例,我们可以上面就是一个html的文件。我们需要在html文件的head中引入jsUnitCore.js以及jsUnitStyle.css两个文件,个文件一个JsUnit的核心框架。还需要加入我们的需要测试的js脚本文件system_under_test.js。
后面可以看到有和junit相同的setup以及teardown,这里的两个函数是测试用例的准备和最后的处理,在每个测试用例之前和之后执行。
testOneThing()以及testAnotherThing()这两个函数就是测试用例,里面完成需要测试的内容。
与Junit相同,在JsUnit中也定义了很多的断言函数。形如assert**的函数都是其断言函数,我们使用这些函数来判定结果是与预期相同。
(2) JsUnit测试集编写
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JsUnit Test Suite</title> <link rel="stylesheet" type="text/css" href="../css/jsUnitStyle.css"> <script type="text/javascript" src="../app/jsUnitCore.js"></script> <script type="text/javascript"> function coreSuite() { var result = new JsUnitTestSuite(); result.addTestPage("tests/jsUnitAssertionTests.html"); result.addTestPage("tests/jsUnitFrameworkUtilityTests.html"); result.addTestPage("tests/jsUnitOnLoadTests.html"); result.addTestPage("tests/jsUnitRestoredHTMLDivTests.html"); result.addTestPage("tests/jsUnitSetUpTearDownTests.html"); result.addTestPage("tests/jsUnitTestManagerTests.html"); result.addTestPage("tests/jsUnitParamsTests.html"); result.addTestPage("tests/jsUnitTestSetUpPages.html"); result.addTestPage("tests/jsUnitTestSuiteTests.html"); result.addTestPage("tests/jsUnitUtilityTests.html"); result.addTestPage("tests/TestPageTest.html"); result.addTestPage("tests/UiManagerTest.html"); return result; } function librariesSuite() { var result = new JsUnitTestSuite(); result.addTestPage("tests/jsUnitMockTimeoutTest.html"); result.addTestPage("tests/jsUnitAjaxTest.html"); return result; } function suite() { var newsuite = new JsUnitTestSuite(); newsuite.addTestSuite(coreSuite()); newsuite.addTestSuite(librariesSuite()); return newsuite; } </script> </head> <body> <p>This page contains a suite of tests for testing JsUnit.</p> </body> </html> |
以上的代码就是测试集的编写,测试集和Junit的概念一致。为了定义一个测试集,需要创建一个名为suite的函数,它会返回一个JsUnitTestSuite的对象。然后通过增加测试用例页面或者其他测试集对象来建立JsUnitTestSuite对象。在上面的例子中最终coreSuite和librariesSuite两个函数返回的JsUnitTestSuite对象在suite函数中加入到了一个JsUnitTestSuite对象中,然后返回该对象。
2 Jasmine
2.1 简介
Jasmine 是一款行为驱动的JavaScript 测试框架,它不依赖于其他任何 JavaScript 框架。它有干净清晰的语法,让您可以很简单的写出测试代码。对基于 JavaScript 的开发来说,它是一款不错的测试框架选择。
2.2 使用步骤初探
(1) 下载Jasmine
下载地址:https://github.com/pivotal/jasmine/releases
Introduction:http://jasmine.github.io/2.0/introduction.html
(2) 目录解析
解压下载下来的zip文件,点开文件夹。看到有如下的目录,其中lib为Jasmine 的源代码。src为一个示例中被测的js文件,spec为编写的测试用例代码,SpecRunner.html为加入
(3) 运行测试用例
解压文件后可以看到有一个文件叫做:SpecRunner.html,点击使用浏览器打开就能够运行相关的测试用例了。
在浏览器中打开运行完后我们可以看到一个结果页面,页面会展示运行的结果信息。
2.3 测试用例编写
(1) 创建一个JS文件,这个文件测试文件
(2) 一个简单的测试用例
describe("when song has been paused", function() { beforeEach(function() { player.play(song); player.pause(); }); it("should indicate that the song is currently paused", function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); it("should be possible to resume", function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); }); }); |
describe 是 Jasmine 的全局函数,作为一个 Test Suite的开始,它通常有 2 个参数:字符串和方法。字符串作为特定 Suite 的名字和标题。方法是包含实现 测试用例集的代码。
Specs通过调用it的全局函数来定义。和describe类似,it也是有2个参数,字符串和方法。每个Spec包含一个或多个expectations来测试需要测试代码。每个it就是一个测试用例。
Jasmine 中的每个expectation是一个断言,可以是true或者false。当每个Spec中的所有expectations都是 true,则通过测试。有任何一个expectation是false,则未通过测试。而方法的内容就是测试主体。
(3) 能运行的测试HTML
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Jasmine Spec Runner v2.0.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.1/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.1/jasmine.css"> <script type="text/javascript" src="lib/jasmine-2.0.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-2.0.1/jasmine-html.js"></script> <script type="text/javascript" src="lib/jasmine-2.0.1/boot.js"></script> <!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script> </head> <body> </body> </html> |
有了上面的文件,直接点开就可以运行了,在2.2节有。
上面文件中红色的字体为加入的测试环境为jasmine框架需要加入的js代码、CSS文件以及一些生成报告的资源文件。紫色字体为引入被测的JS代码的路径。绿色字体为加入测试的JS代码的路径。
2.4 运行
3 JSLint
3.1 简介
JSLint是一款 JavaScript语法检查和验证工具,可以扫描JavaScript源代码来查找问题。JSLint不是一款开源的软件,它使用纯JavaScript编写。JSLint定义了一个专业的语法规则和建议的集合。
如果JSLint发现一个问题,JSLint就会显示描述这个问题的消息,并指出错误在源代码中的大致位置。有些编码风格约定可能导致未预见的行为或错误,JSLint除了能指出这些不合理的约定,还能标志出结构方面的问题。尽管JSLint不能保证逻辑一定正确,但确实有助于发现错误,这些错误很可能导致浏览器的 JavaScript引擎抛出错误。
JSLint 执行代码质量检测的原理核心在于用户设定的规则集。JSLint 默认提供的规则集包含了 Web 开发人员多年积累下来的认为不好的开发风格,我们可以根据自己项目的需求选择构建一套特定的规则。JSLint 将根据它进行对 JavaScript 脚本的扫描工作,并给出相应的问题描述信息。
3.2 JSLint用法初探
(1) 直接使用http://www.jslint.com/网址进行检测。在输入框中你的JavaScript脚本。然后点击JSLint按钮,我们就可以看到了JSLint说到的我们的错误之处。
这个页面还提供一些其他的规则,如果你不选择这些规则,则按照JSLint的默认的规则进行
4 Qunit
4.1 简介
Qunit是一款由Jquery团队开发的JavaScript单元测试框架。它原本是Jquery团队为自己的框架开发的一套测试框架,它可以被用于jQuery、jQuery UI、jQuery移动项目以及其他更广义的JavaScript代码,包括Qunit自身。
4.2 使用步骤初探
(1) 下载框架
需要下载的内容有两个:qunit-1.15.0.js和qunit-1.15.0.css两个文件,分别为Qunit的单元测试框架JS代码以及生成报告所需的CSS结构。
下载地址:http://qunitjs.com/
(2) Qunit可运行的HTML环境配置
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>QUnit basic example</title> <link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.15.0.css"> </head> <body> <div id="qunit"></div> <div id="qunit-fixture"></div> <script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script> <script> QUnit.test( "a basic test example", function( assert ) { var value = "hello"; assert.equal( value, "hello", "We expect value to be hello" ); }); </script> </body> </html> |
上面就是一个简单的用例,直接点击这个HTML文件在浏览器中打开就可以运行响应的代码,其中红色的字就是QUnit框架,绿色字体的为一条测试用例。当然测试用例也可以单独的写在一个文件中,然后引入到页面上面即可。
(3) Qunit可运行的HTML环境配置
点击这个HTML文件后生成的结果如下:
看一下这个结果,在HTML中的head元素的title中定义了这个测试的标题。标题下面是对于结果的筛选。
Hide passed tests:这个选项勾选后会将通过的测试用例隐藏起来,这个对于运行比较多的测试用例来讲非常有用。
Check for Globals:如果不小心引入了一些全局变量修改,会将这个测试标识为failed,这里可以看到一些全局变量的列表是否有变化。
No try-catch:就是如果用例抛出了一个异常,那么就会停止给出抛出异常的地方。
下面就是一个测试用例的概述,里面包括测试用例运行的时间、断言的成功失败数。注意这里的概述部分里面的数字是说断言的数量而不是测试用例的数量。但是可能一个测试用例包含好几个断言。
4.3 测试用例编写
(1) 测试用例编写例子
<div id="qunit-fixture"></div> <script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script> <script> QUnit.test( "a basic test example", function( assert ) { var value = "hello"; assert.equal( value, "hello", "We expect value to be hello" ); }); </script> |
如果要得到一个比较好看的结果,需要将测试用例包含在一个id为qunit-fixture的div中,因为在这个标记中每运行一个用例都会重置里面的元素,以保证测试的独立性。如果你在其他的标记下面修改和删除了某些元素,那么将会导致测试的非独立性。
每个测试用例都以QUnit.test(String,fuction(assert){});这样的形式编写的,一个测试用例包括两个参数第一个是这个测试的名字,第二个参数是实际的测试用例方法。
(2) QUnit断言
QUnit共提供了8个断言,常用的断言有:
a) ok(truthy[,message]): assert.ok( true, "true succeeds" );
b) equal(actual,expected[,message]): assert.equal( 0, 0, "Zero, Zero; equal succeeds" );
c) deepEqual( actual, expected [, message ] ):
var obj = { foo: "bar" };
assert.deepEqual( obj, { foo: "bar" }, "Two objects can be the same in value" )
这个和equal不同点在于b)用的是”==”来判定actual和expected,而这个用的是”===”
(3) 异步请求测试
现在的页面都是大量的使用了AJAX的方式来实现,当一个测试用例遇到了中断、异步调用等等时,它不会异步请求返回结果,而是直接执行测试的后面的部分。在QUnit中,使用asynTest方法配合使用expect方法以及QUnit.start()方法可以来实现异步调用的测试。当阻塞返回了,能够恢复运行。
QUnit.asyncTest( "asynchronous test: video ready to play", function( assert ) { expect( 1 ); var $video = $( "video" ); $video.on( "canplaythrough", function() { assert.ok( true, "video has loaded and is ready to play" ); QUnit.start(); }); }); |
(4) 测试用户的行为
在javascript,有一些函数不能够只通过调用方法就能够测试,有一些匿名方法不能直接调用,而是通常与事件进行绑定的。在JQuery中有一些trigger()的方法能够帮助我们来模拟事件从而进行测试。
(5) 测试集
你可以使用QUnit.module()方法来将你的测试用例分组。