网页前端持续集成(2) - qunit+JSCoverage+PhantomJS使用小记

来源:互联网 发布:下载easyrecovery软件 编辑:程序博客网 时间:2024/06/15 22:29

今年早些时候为公司项目做过一些网页前端程序的持续集成(CI),在过去的几个月中不断地给不同的人讲解过之后,我决定开一篇介绍一下。

公司项目是一个ASP.net的网站,其中核心是一些JavaScript 的框架库以及扩展函数。基本目标是在Jenkins上集成单元测试(Unit Test), 和代码覆盖率的统计。由于是前端程序,所以我们采用qunit来做单元测试,代码覆盖率使用JSCoverage(使用简介可移步helloworld)。不过CI需要的是后台自动运行各个步骤,怎么办?我们找到了一个很好用的工具PhantomJS, 它通过一个webkit浏览器内核,实现了后台隐式的打开网址或网页,可以极大的方便前端程序的测试。那么,怎么把这几样宝贝集成起来?这篇介绍的就是这样一个windows上的例子,把它做一遍,可以对这几项工具有基本的了解。

0. 环境搭建

下载qunit, JSCoverage, PhantomJS, ant(apache-ant)。除qunit外,把其余三项的bin目录添加到环境变量Path中去。

用到的压缩包下载地址会列在文末。其解压缩后的根目录列表如下,数目稍多因为把qunit, jscoverage,phantomjs的exe和一些默认配置辅助文件都放过来了,省得来回切换。

1. 定义待测试JavaScript 文件及函数

testme.js:

function add(){    var sum =0;    var count=0;    for (var i=0; i<arguments.length; i++){           if(arguments[i] < 10){            sum += arguments[i];            count++;        }    }    if(count < arguments.length){        for (var i=0; i<arguments.length; i++){               if(arguments[i] >= 10){                sum += arguments[i];               }        }        }    return sum;   }
testme02.js:

function divide(){if(arguments.length == 0){    return 0;        }        if(arguments[0] == 0)    return 0;var quotient = arguments[0];           for (var i=1; i<arguments.length; i++){            if(arguments[i] == 0){                continue;            }else{        quotient /= arguments[i];            }        }    return quotient;   } 

2. 编辑待测试网页
testme.test.html

<!DOCTYPE html>  <html>  <head>      <!-- we need QUnit as a test runner -->      <link rel="stylesheet" href="qunit.css" type="text/css" media="screen" />      <script src="qunit.js"></script>        <!-- we'd like to have the file we're going to test -->      <script src="testme.js"></script>    <script src="testme02.js"></script>         <script src="test-support.js"></script>    <!-- and finally lets write some tests -->      <script>test("add(1, 2, 10, 9)", function(){equal(add(1, 2, 10, 9), 22);});test("divide ()", function(){equal(divide(), 0);});test("divide (0, 1, 2)", function(){equal(divide(0, 1, 2), 0);});test("divide (10, 0, 5)", function(){equal(divide(10, 0, 5), 2);});test("add (int, divide())", function(){equal(add(1, divide(12, 3)), 5);});    </script>    <style>          .code {               white-space: pre;               font-family: courier new;               width: 100%;                       }                      .miss {               background-color: #FFFFFF;           }                      .hit {               background-color: #94FF7C;           }                      .undef {               background-color: #00FF9E;           }               </style></head>  <body>       <h1 id="qunit-header">QUnit Tests</h1>       <h2 id="qunit-banner"></h2>       <div id="qunit-testrunner-toolbar"></div>       <h2 id="qunit-userAgent"></h2>       <ol id="qunit-tests"></ol>       <div id="qunit-fixture"></div>       </body>  </html>

其中写了5个测试用例,并加载了qunit.js

3.在build.xml中定义目录结构。

<project name="jsunittests" basedir="." default="main">      <property name="basedir" location="."/>    <property name="builddir" location="${basedir}/target"/>    <proerty name="jstestdir" location="${builddir}/testjs"/>    <property name="jsdir" location="${jstestdir}/js"/>    <property name="jsinstrumenteddir" location="${jstestdir}/jsinstrumented"/>    <property name="testhtmdir" location="${builddir}/testhtm"/>    <condition property="phantom.filename" value="phantomjs.bat"><os family="windows"/></condition>      <property name="jscoverage.filename" value="jscoverage.bat"/>...</project>
$basedir 是当前目录,$jstestdir下的两个目录存放待测试js文件,其中\js是原始文件,\jsinstrumented是经过JSCoverage注入过锚标记的文件。$testhtmdir是测试用的HTML目录。
4.在build.xml中定义各项任务

任务clean是清空全部已有文件,prep是准备工作,把所有用到的文件拷贝到目标目录中去。

    <target name="clean">          <delete dir="${builddir}"/>      </target>         <target name="prep">          <mkdir dir="${builddir}"/>        <mkdir dir="${jstestdir}"/>        <mkdir dir="${jsdir}"/>        <mkdir dir="${jsinstrumenteddir}"/>        <mkdir dir="${testhtmdir}"/>        <!--copy test source js files to target-->        <copy todir="${jsdir}">               <fileset dir="${basedir}">                   <include name="testme.js" /><include name="testme02.js" />            </fileset>           </copy>       <!-- run jscoverage to produce a version of the file instrumented for code coverage -->           <exec executable="${jscoverage.filename}" failonerror="true">               <arg value="${jsdir}"/>               <arg value="${jsinstrumenteddir}"/>           </exec>           <!-- copy our test htm files and modify them to point to the coverage indexed version of the test file. -->          <copy todir="${testhtmdir}">               <fileset dir="${basedir}">                   <include name="*.test.html" />               </fileset>           </copy>                         <!-- copy core resources to testhtmdir so we can load them with same paths as when executing test htm files directly -->           <copy todir="${testhtmdir}">               <fileset dir="${jsinstrumenteddir}">                   <include name="**/*.js" />                   <exclude name="jscoverage.js"/>               </fileset>           </copy>                          <copy todir="${testhtmdir}">               <fileset dir="${basedir}">                   <include name="test-support.js" />                   <include name="run-qunit.js" />                   <include name="qunit.css" />                   <include name="qunit.js" />            </fileset>           </copy>          </target>  
接下来,定义实际做测试的任务jstest。我们用PhantomJS打开一个HTML文件,这个html包含qunit文件,并调用已经带有JSCoverage标记的JS待测试函数。这样如果运行成功,我们可以得到测试例子的通过率和代码覆盖率。

    <target name="jstest">        <!--Run all tests via phantom, fail if tests fail. Execute all files with extension .test.htm. -->        <apply executable="${basedir}/${phantom.filename}" failonerror="true" dir="${testhtmdir}" relative="false">           <arg value="run-qunit.js"/>           <srcfile/>         <!--arg[0]--> <fileset dir="${testhtmdir}">               <include name="*.test.html" />           </fileset> <!--argp[1]--> <arg value="${basedir}"/>       </apply>                   </target> 
这里的run-qunit.js是PhantomJS的启动文件,它从中得知该从哪个网址/网页启动,导入后又该执行什么动作。之后的第一个参数是输入的网页文件,第二个参数是输出路径。

到目前为止,各项任务定义完毕,可以调用了。

    <target name="main" depends="clean, prep, jstest">      </target>  

5. 编辑jscoverage.bat

注意定义成本地的绝对路径。最后一行的末尾 %* 意思是接受后续的参数。

set JSCov_Dir=D:\Product\VEF-CI-ref\jsunit\%JSCov_Dir%\jscoverage.exe %*

6. 编辑phantomjs.bat

set PhantomJS_Dir=D:\Product\VEF-CI-ref\jsunit\%PhantomJS_Dir%/phantomjs.exe %*

7. 编辑run-qunit.js

这个文件告诉PhantomJS如何启动。最重要的是要定义onReady函数,在网页启动完成后执行。这里我们仅仅基于JSCoverage的各行执行次数,计算了总的文件覆盖率。

额外的还有test-support.js文件,定义了一些辅助函数。因这两文件较长,此处就不列了,文件细节可以在压缩包中找到。

8.执行ant

运行成功的输出如下,注意到这里两个文件的覆盖率均为100%。


9.检查输出网页

打开.\target\testhtm\testme.test.html,可以看到qunit的执行结果。


打开.\target\testhtm\testme.coverage.testme.js.html,能够看到以不同颜色标示的代码覆盖部分。怎么样?还算清楚吧:)有同学可能注意到了,这些颜色就是在testme.test.html中<style>部分定义的。


当然 testme.coverage.testme02.js.html也能带来同样的显示。

小结:

1. qunit+JSCoverage+PhantomJS 的组合能够满足前端程序对于持续集成的基本需要。对于目标程序,其开发语言限制较少,比如Java完全可以。

2. 如果想要集成到Jenkins的平台中,只需要将JSCoverage, PhantomJS等执行步骤单独设置成Jenkins的一个任务即可。

3. 如果想把相应的测试结果,代码覆盖率等输出到文件,可以编辑PhantomJS.exe 后紧跟的第一个文件,比如这里的run-qunit,js,在onReady()函数中加入你所需要的部分。

注:压缩包下载地址phantomjs-jscoverage.zip

0 0
原创粉丝点击