用Java(JUnit4)對JavaScript(含Ajax)腳本進行單元測試

1、背景

由於原來採用過Rhino(JS解析引擎,新版JDK中也默認包含另一個解析引擎)來在Java環境中解析JavaScript並運行其中的方法。最近看到有人在問題裏提問,模擬Ajax請求的問題。因此就想看看有沒有方法經過Rhino來實現Ajax請求的模擬。 javascript

2、分析

經過上網檢索,發現能夠採用Envjs,一個純js方式在無瀏覽器環境下模擬瀏覽器的行爲,而且與Rhino有集成。這樣我就能夠實現用Java來處理孤立js中的Ajax請求。 html

3、開發

一、項目目錄結構

main中my.js爲要測試的JavaScript,jquery-1.9.1.js爲依賴。
test中AjaxTest.java爲單元測試類,test.html爲測試頁面,env.rhino.1.2.js爲Envjs依賴。 java

二、my.js(Jquery的ajax)

function myFunction(id) {

    $.ajax({
        url:"/ajaxservice",
        type:"POST",
        data:{id:id},
        dataType:"json",
        success:function (msg) {
            $("#log").text(msg.name);
        }

    });


}

這個myFunction實際上就是調用了Jquery的ajax來請求ajaxservice,並把返回的json對象中的name顯示在id爲log的元素中。 jquery

三、test.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title></title>
    <meta content="text/html;charset=utf-8">
</head>
<body>

      <div id="log">ilog</div>

</body>
</html>
須要測試的my.js並不包含任何頁面爲了測試my.js的功能須要先有一個頁面來模擬Ajax請求,並對返回操做作出響應。


四、AjaxTest.java單元測試類

package org.noahx.ajaxtest;


import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ScriptableObject;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;


/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 4/8/13
 * Time: 9:21 PM
 * To change this template use File | Settings | File Templates.
 */
public class AjaxTest {


    private static int port = 18080;


    private static String testUrl = "http://127.0.0.1:" + port + "/test.html";


    private Context cx;
    private ScriptableObject scope;


    @BeforeClass
    public static void prepareHttpService() throws Exception {
        Server server = new Server(port);
        ResourceHandler resourceHandler = new ResourceHandler();
        resourceHandler.setBaseResource(Resource.newClassPathResource("/org/noahx/ajaxtest/html"));


        HandlerList handlers = new HandlerList();
        handlers.setHandlers(new Handler[]{resourceHandler, new AjaxHandler()});
        server.setHandler(handlers);
        server.start();
    }


    public static class AjaxHandler extends AbstractHandler {


        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            if ("/ajaxservice".equals(target)) {
                System.out.println("id=" + request.getParameter("id"));
                response.setContentType("application/json;charset=utf-8");
                response.setStatus(HttpServletResponse.SC_OK);
                baseRequest.setHandled(true);
                response.getWriter().println("{\"name\":\"張三\"}");  //返回json "name":"張三"
            }
        }
    }


    @Before
    public void prepareRhinoContext() throws Exception {


        //初始化rhino
        cx = ContextFactory.getGlobal().enterContext();
        cx.setOptimizationLevel(-1);
        cx.setLanguageVersion(Context.VERSION_1_5);
        scope = cx.initStandardObjects();




        //預製js驗證與調試方法
        String printFunction = "function print(message) {java.lang.System.out.println(message);}";
        String assertEqualsNumFunction = "function assertEqualsNum(a,b) {org.junit.Assert.assertEquals(a,b,1e-15);}";
        String assertNotEqualsNumFunction = "function assertNotEqualsNum(a,b) {org.junit.Assert.assertNotEquals(a,b,1e-15);}";
        String assertEqualsStrFunction = "function assertEqualsStr(a,b) {org.junit.Assert.assertEquals(a,b);}";
        String assertNotEqualsStrFunction = "function assertNotEqualsStr(a,b) {org.junit.Assert.assertNotEquals(a,b);}";


        cx.evaluateString(scope, printFunction, "print", 1, null);
        cx.evaluateString(scope, assertEqualsNumFunction, "assertEqualsNum", 1, null);
        cx.evaluateString(scope, assertNotEqualsNumFunction, "assertNotEqualsNum", 1, null);
        cx.evaluateString(scope, assertEqualsStrFunction, "assertEqualsStr", 1, null);
        cx.evaluateString(scope, assertNotEqualsStrFunction, "assertNotEqualsStr", 1, null);


        loadJS("env.rhino.js", "/org/noahx/ajaxtest/env.rhino.1.2.js"); //加載Envjs


    }


    @Test
    public void testJqueryAjax() throws Exception {
        loadJS("jquery.js", "/org/noahx/ajaxtest/jquery-1.9.1.js"); //加載jquery
        loadJS("my.js", "/org/noahx/ajaxtest/my.js");         //加載要測試的js


        run("window.location = \"" + testUrl + "\"");          //加載測試js的測試html


        run("assertEqualsStr($(\"#log\").text(),\"ilog\");");   //從test.html中取log元素中的text,應該爲ilog


        run("myFunction(\"myid123\");");


        run("Envjs.wait();");   //Envjs等待,模擬異步ajax響應


        run("assertEqualsStr($(\"#log\").text(),\"張三\");");   //從test.html中取log元素中的text,應該爲張三


    }


    @Test
    public void testPrint() throws Exception {
        run("print('hello js!');");
    }


    @Test
    public void testNotEqualsNum() throws Exception {
        run("assertNotEqualsNum(1,2);");
    }


    @Test
    public void testEqualsNum() throws Exception {
        run("assertEqualsNum(1,1);");
    }


    @Test
    public void testEqualsStr() throws Exception {
        run("assertEqualsStr(\"abc\",\"abc\");");
    }


    @Test
    public void testNotEqualsStr() throws Exception {
        run("assertNotEqualsNum(1,2);");
    }




    private void loadJS(String sourceName, String classpathURI) {
        String js = null;
        InputStream inputStream = null;
        try {
            inputStream = getClass().getResourceAsStream(classpathURI);
            js = IOUtils.toString(inputStream, "UTF-8");//設置默認js文件編碼爲utf-8
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(inputStream);
        }


        cx.evaluateString(scope, js, sourceName, 1, null);
    }




    private String run(String js) throws Exception {
        Object result = cx.evaluateString(scope, js, "run", 1, null);
        return Context.toString(result);
    }


    private void waitSec(int sec) {
        try {
            Thread.sleep(1000 * sec);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }




}

 

  
  
  
  

 
a、@BeforeClass時啓動內嵌Jetty服務器來響應test.html的請求與/ajaxservice請求。
b、@Before時對Rhino進行初始化,加入一些預製js調試方法。
c、testJqueryAjax方法中用loadJs加載jquery與my.js。
d、調用window.location模擬瀏覽器顯示頁面。
e、調用myFunction發起Ajax請求,Jetty會在AjaxHandler中收到請求並響應json數據。
f、myFunction中會根據返回數據修改頁面顯示div(div id="log")
g、使用自定義的js方法assertEqualsStr來驗證dom元素是否被修改正確


五、pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.noahx.ajaxtest</groupId>
    <artifactId>ajax-test</artifactId>
    <version>1.0</version>


    <dependencies>

        <dependency>
            <groupId>org.mozilla</groupId>
            <artifactId>rhino</artifactId>
            <version>1.7R4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>8.1.10.v20130312</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>


    </dependencies>


</project>

4、總結

能夠用這樣的方式單元測試js確實我也沒有想到,你們也能夠用這樣方式來模擬頁面行爲得到動態頁面數據。 ajax

源碼下載: apache

http://sdrv.ms/10HUv7y json

相關文章
相關標籤/搜索