由於原來採用過Rhino(JS解析引擎,新版JDK中也默認包含另一個解析引擎)來在Java環境中解析JavaScript並運行其中的方法。最近看到有人在問題裏提問,模擬Ajax請求的問題。因此就想看看有沒有方法經過Rhino來實現Ajax請求的模擬。 javascript
經過上網檢索,發現能夠採用Envjs,一個純js方式在無瀏覽器環境下模擬瀏覽器的行爲,而且與Rhino有集成。這樣我就能夠實現用Java來處理孤立js中的Ajax請求。 html
main中my.js爲要測試的JavaScript,jquery-1.9.1.js爲依賴。
test中AjaxTest.java爲單元測試類,test.html爲測試頁面,env.rhino.1.2.js爲Envjs依賴。 java
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
<!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請求,並對返回操做作出響應。
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請求。
<?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確實我也沒有想到,你們也能夠用這樣方式來模擬頁面行爲得到動態頁面數據。 ajax
源碼下載: apache