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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/teaspring/article/details/17266247

今年早些时候为公司项目做过一些网页前端程序的持续集成(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

猜你喜欢

转载自blog.csdn.net/teaspring/article/details/17266247