侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

用Java(JUnit4)对JavaScript(含Ajax)脚本进行单元测试

2022-06-19 星期日 / 0 评论 / 0 点赞 / 73 阅读 / 12081 字

一、背景 因为原来采用过Rhino(JS解析引擎,新版JDK中也默认包含另外一个解析引擎)来在Java环境中解析JavaScript并运行其中的方法。最近看到有人在问题里提问,模拟Ajax请求的问

一、背景

因为原来采用过Rhino(JS解析引擎,新版JDK中也默认包含另外一个解析引擎)来在Java环境中解析JavaScript并运行其中的方法。最近看到有人在问题里提问,模拟Ajax请求的问题。所以就想看看有没有方法通过Rhino来实现Ajax请求的模拟。

二、分析

通过上网检索,发现可以采用Envjs,一个纯js方式在无浏览器环境下模拟浏览器的行为,并且与Rhino有集成。这样我就可以实现用Java来处理孤立js中的Ajax请求。

三、开发

1、项目目录结构

main中my.js为要测试的JavaScript,jquery-1.9.1.js为依赖。
test中AjaxTest.java为单元测试类,test.html为测试页面,env.rhino.1.2.js为Envjs依赖。

2、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的元素中。

3、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请求,并对返回操作做出响应。


4、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元素是否被修改正确


5、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>

四、总结

可以用这样的方式单元测试js确实我也没有想到,大家也可以用这样方式来模拟页面行为获得动态页面数据。

源码下载:

http://sdrv.ms/10HUv7y

广告 广告

评论区