3 利用Java 请求实现
这里我们以新版本的电子商务登录作为例子。
1)在Eclipse中建立项目,在这个项目中建立api和utils两个包。
2)在包api下建立IHRMLogin.java,内容如下。
package api; import utils.HTTPRequestUtils; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import com.alibaba.fastjson.JSONObject; public class IHRMLogin { public JSONObject headers = new JSONObject(); public JSONObject login_data = new JSONObject(); public String url; public IHRMLogin(){ //url 为请求的目标地址 url = "http://192.168.1.3:8080/sec/46/jsp/index.jsp"; } public String loginIHRM(String username, String password, String time) { String Params = "username="+username+"&password="+getSHA256StrJava(password)+"&time="+time; return HTTPRequestUtils.sendPost(this.url, Params); } // SHA-256散列函数的Java实现 public String getSHA256StrJava(String str){ MessageDigest messageDigest; String encodeStr = ""; try { messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(str.getBytes("UTF-8")); encodeStr = byte2Hex(messageDigest.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return encodeStr; } private static String byte2Hex(byte[] bytes){ StringBuffer stringBuffer = new StringBuffer(); String temp = null; for (int i=0;i<bytes.length;i++){ temp = Integer.toHexString(bytes[i] & 0xFF); if (temp.length()==1){ //1得到一位的进行补0操作 stringBuffer.append("0"); } stringBuffer.append(temp); } return stringBuffer.toString(); } public static void main(String[] args){ IHRMLogin ihrmLogin = new IHRMLogin(); String response = ihrmLogin.loginIHRM("cindy","123456","360"); System.out.println(response); } }
IHRMLogin构造函数中定义请求的目标地址;loginIHRM函数中定义参数,然后用HTTPRequestUtils.sendPost()函数向服务器发送POST HTTP请求。函数getSHA256StrJava实现SH256散列算法,在前端通过js文件来实现。
3)在utils包下建立HTTPRequestUtils.java。
package utils; import java.io.*; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; import api.IHRMLogin; public class HTTPRequestUtils { /** * 向指定URL发送GET方法的请求 * * @param url *发送请求的URL * @param param *请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return URL 所代表远程资源的响应结果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立实际的连接 connection.connect(); // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 发送POST方法的请求 * * @param url * 发送请求的 URL * @param param * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); //获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 获取所有响应头字段 Map<String, List<String>> map = conn.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送 POST 请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } public static void main(String[] args) { IHRMLogin loginApi = new IHRMLogin(); String url = "http://192.168.1.3:8080/sec/46/jsp/index.jsp"; String username = "cindy"; String password = "123456"; String time = "360"; String Params = "username="+username+"&password="+loginApi.getSHA256StrJava(password)+"&time="+time; String result = HTTPRequestUtils.sendPost(url, Params); System.out.println(result); } }
这里我们采用java.net.URLConnection 来实现HTTP请求。sendGet是发送Get请求的方法;sendPost是发送POST请求的方法。顺便说一句,如果要在请求中加入cookies信息,可使用语句conn.setRequestProperty("Cookie", "Key=Value"); 但是我发现这个语句在Get请求中是有效的,而在POST请求中是无效的。
3)打开WEB服务器,运行HTTPRequestUtils.java或IHRMLogin.java都应该通过。如图6所示。
图6 测试HTTPRequestUtils.java和IHRMLogin.java
4)在utils包中建立JMeter的接口Java文件:TestIHRMLogin.java。
package utils; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient; import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; import org.apache.jmeter.samplers.SampleResult; import api.IHRMLogin; public class TestIHRMLogin implements JavaSamplerClient { private String username; private String password; private String time; public void setupTest(JavaSamplerContext javaSamplerContext) { this.username = javaSamplerContext.getParameter("username"); this.password = javaSamplerContext.getParameter("password"); this.time = javaSamplerContext.getParameter("time"); } public SampleResult runTest(JavaSamplerContext javaSamplerContext) { SampleResult result = new SampleResult(); IHRMLogin loginApi = new IHRMLogin(); // 获取当前线程编号 String threadName = Thread.currentThread().getName(); System.out.println(threadName); // 设置返回结果标签的名称 result.setSampleLabel("ihrm-" + threadName); // 在Jmeter的GUI中展示请求数据 result.setSamplerData("username="+this.username+"&password="+loginApi.getSHA256StrJava(this.password)+"&time="+this.time); // 开始事务,开始计算时间 result.sampleStart(); try { String response = loginApi.loginIHRM(this.username, this.password,this.time); // 把返回结果设置到SampleResult中 result.setResponseData(response, null); // 设置返回结果的为Text类型 result.setDataType(SampleResult.TEXT); result.setSuccessful(true); // 输出结果到控制台 } catch (Throwable e) { result.setSuccessful(false); e.printStackTrace(); } finally { // 结束事务,计算请求时间 result.sampleEnd(); } return result; } public void teardownTest(JavaSamplerContext javaSamplerContext) { } public Arguments getDefaultParameters() { Arguments arguments = new Arguments(); arguments.addArgument("username", ""); arguments.addArgument("password", ""); arguments.addArgument("time", ""); return arguments; } }
在这个Java文件中包括以下几个步骤,建立4个方法。
- 请求类继承 JavaSamplerClient。
- 为请求创建需要的参数,实现public Arguments getDefaultParameters() 方法
- 编写请求初始化方法,只执行一次,实现public void setupTest(JavaSamplerContext context) 方法
- 编写请求循环执行方法,执行多次,实现public SampleResult runTest(JavaSamplerContext context) 方法
- 编写请求结束方法,实现public void teardownTest(JavaSamplerContext context) 方法。
5)将这三个文件打成jar包。将打好的jar包放在%JMETER_HOME%/lib/ext/目录下(参见第1节第2)-6)步)。
6)启动JMeter,建立一个项目,首先建立线程组,右键点击线程组,在弹出菜单中选择“添加->取样器->Java请求”。
7)在下拉列表中就可以找到utils.TestIHRMLogin了,在里面输入用户名,密码和cookies保持时间,如图7所示。
8)添加察看结果树。
9)运行就可以在察看结果树中看到结果了。
图7 在Java Request
10)由于默认采用GBK,编码模式,所有出来的代码为乱码。右键点击线程组,在弹出菜单中选择“添加->后置处理器->BeanShell 后置处理程序”。
11)在Script中加入:“prev.setDataEncoding("UTF-8");” 即可,如图8所示。
图8 BeanShell后置处理程序中设置响应结果编码为UTF-8
12)运行后在察看结果树中显示如图9所示。
图9 Java Request的运行结果
对于BeanShell 后置处理程序将在第4.2-1节中进行介绍;Java 取样器将在第4.3-1节中进行介绍。本节的Java代码在本书的配套代码java\JMeter目录下;jmx为Java_Request.jmx。
到此完毕,我们的接口测试的内容全部结束。保存目前所有的代码为ebussines_interface.jmx。复制ebussines_interface.jmx改名为ebussines_all.jmx。打开ebussines_all.jmx作如下修改。
- 删除循环控制器下面的JDBC Connection Configuration、JDBC Request、通过MySQL获取用户名和密码的正则表达提取器3个元件。
- 删除登录HTTP请求下面的BeanShell断言、获取加密后的password BeanShell预处理程序2个元件。
- 确定或者修改商品列表HTTP请求中的username值为{username}; password值为{__digest(SHA-256,${password},,,)。然后删除商品列表HTTP请求下面的商品列表信息响应断言1个元件。
- 删除商品列表(new)下面的商品列表(new) 商品列表(new)XML断言、商品列表(new) XPath2 Assertion 2个元件。
- 删除setUp和tearDown线程组。
ebussines_interface.jmx如图10所示;ebussines_all.jmx如图11所示。
ebussines_all.jmx与第5.4.2节中保存的ebussine_login.jmx将作为后面性能测试使用。
图10
图11 ebussines_all.jmx