1 简单的上传和下载
1.1 文件上传接口测试
选择Files Upload,填写相应参数:
- File Path:填写绝对路径
- Parameter Name:根据实际请求中的参数填写
- MIME Type:根据实际请求中的参数填写
- Use multipart/from-data for HTTP POST 勾选上(发现在5.5版本中,不勾选也没影响,发送的请求默认就时multipart/from-data,其他版本未进行验证)
几点说明:
(1) MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。(来源:百度百科)
(2) 实际使用中发现一个,MIME Type这个参数不论填写什么,都不影响文件的正确上传,但是必须要有值。结合上面MIME的简介,猜想这个值对文件的解析是没有作用的,很多系统文件上传都是指定模板的,并不需要这个参数(仅为猜想)
(3) 很多文章里面说Client implementation选择java,实际使用中没有勾选,也不影响文件的上传。
实际上很多使用java的是为了避免特殊字符被编码,而这跟post请求的编码方式有关,FORM表单的 enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。
值 | 描述 |
---|---|
application/x-www-form-urlencoded | 在发送前编码所有字符(默认) |
multipart/form-data | 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。 |
application/json | 在发送前编码所有字符(默认) |
text/plain | 空格转换为 “+” 加号,但不对特殊字符编码。 |
(4) 查了一下java和HttpClient4的介绍。主要区别为
Java:选择压测时,链接是复用的(代码中的http调用都加了连接池)
httpclient4:压测时,每请求一次都创建一个新的链接,(jmeter5.0以前默认关闭了连接复用,5.0上是打开的:即每请求一次都会创建一个新的链接)
从JMeter 5.0开始,当使用默认的HC4实现时,JMeter将在每个线程组迭代时重置HTTP状态(SSL状态+连接)。如果您不想要此行为,请设置httpclient.reset_state_on_thread_group_iteration = false
所以httpclient4 在连接复用设置打开的情况下,压测结果与java的是不一样的,因为java复用链接,httpclient4每次连接都会重新建立tcp连接,如果httpclient4吞吐量过低,需要考虑网络带宽的限制
java实现适合压榨性测试,httpclient4适合真实场景的模拟。
(5) 可能在application/x-www-form-urlencoded下,使用java特殊字符没有编码是一个巧合,并不是特意为之?
1.2 文件下载接口测试
-
文件下载,如果仅测试接口是否返回了数据,而不把文件保存到本地,和常规的接口测试是一样的,只不过返回的数据是字节流,我们看起来像是乱码(如何在结果树中直接查看文件内容,可参看文章《JMeter在结果树中直接查看文件内容》)
-
可以添加【Size Assertion】进行断言。因为每一次的大小会有变化,可以将返回的大小数据适当降低,然后使用大于或大于等于进行判断。
2 文件下载到本地
2.1 固定文件路径
- 把文件下载到本地,需要添加BeanShell PostProcessor,然后写入代码。
- 如果不指定具体的存储路径,会默认将默认存在JMEGER_HOME/bin目录下。
- 或者直接指定类似“D://Download/下载的文件.xlsx”的绝对路径。
import java.io.*;
byte[] result = prev.getResponseData(); //获取请求的返回
String fileName = "下载的文件.xlsx"; //代表存放文件的位置和文件名,只有文件名,默认存在JMEGER_HOME/bin目录下
File file = new File(fileName);
FileOutputStream out = new FileOutputStream(file);
out.write(result);
out.close();
2.2 相对文件路径
String fileName = "../下载的文件.xlsx";//在JMEGER_HOME/bin目录的上一级目录下,即存在JMEGER_HOME目录下
2.3 根据脚本路径存放
- 获得执行脚本所在的路径,再获取其父路径,然后和指定目录及文件名拼接,实现存在脚本路径的父路径下的result目录中,保存文件之前先进行删除,避免文件存在,jmeter报错。
- 分隔符问题:windows分割符为\,linux为/,当前windows也可以识别/,因此可以统一使用/,如果在windows下使用\,需要转义一下,即使用\,另外还可以通过System.getProperty(“file.separator”)来获取系统分隔符。
fileName = strParentDirectory +"/result/" + fileName;
ileName = strParentDirectory +"\\result\\" + fileName; //winows下也可以
fileName = strParentDirectory +System.getProperty("file.separator") +"result"+System.getProperty("file.separator") + fileName; //使用系统分割符
完整的代码:
import java.io.*;
import org.apache.jmeter.services.FileServer;
String baseDir=FileServer.getFileServer().getBaseDir(); //获取当前脚本的路径
log.info("baseDir="+baseDir);//打印出来
File file = new File(baseDir);//创建file对象
String strParentDirectory = file.getParent();//获取父目录
log.info("strParentDirectory="+strParentDirectory);//打印出来
byte[] result = prev.getResponseData(); //获取请求的返回
String fileName = "下载的文件.xlsx";
fileName = strParentDirectory +"/result/" + fileName;
File file = new File(fileName);
file.delete();//先进行删除,避免文件存在报错
FileOutputStream out = new FileOutputStream(file);
out.write(result);
out.close();
注意:result目录应该已经存在
2.4 文件名称处理
- 可以通过正则表达式,来获取响应头中的Content-Disposition内容,然后再使用split()方法,逐步提取文件名称
- 要解析的请求头Content-Disposition示例如下:ContentDisposition:attachment;filename=AA31_VCU_ParseResult.xls
import java.io.*;
import org.apache.jmeter.services.FileServer;
import java.util.regex.*;
String baseDir=FileServer.getFileServer().getBaseDir(); //获取当前脚本的路径
//log.info("baseDir="+baseDir);//打印出来
String strParentDirectory = file.getParent();//获取父目录
byte[] result = prev.getResponseData(); //获取请求的返回体
String headers= prev.getResponseHeaders(); //获取返回的响应头
//log.info("###################"+headers); //jmeter console界面输出该信息
String pattern="Content-Disposition:(.*)";
Pattern r=Pattern.compile(pattern);//创建Pattern对象
Matcher m = r.matcher(headers);//创建matcher对象
String fileName = "template.xlsx";//默认的文件名称
if (m.find()){
token=m.group(1).trim();
String[] str = token.split(";");
String a = str[1];
String[] str1 = a.split("=");
// log.info(str1[1]);
fileName = URLDecoder.decode(str1[1], "UTF-8");
log.info("fileName=" + fileName);
}else{
log.info("No Match!");
}
fileName = strParentDirectory +"/result/" + fileName;
File file = new File(fileName);
file.delete();//先进行删除,避免文件存在报错
FileOutputStream out = new FileOutputStream(file);
out.write(result);
out.close();
2.5 文件下载成功或失败判断
可添加以下代码对文件是否下载成功进行判断
if(file.exists()){
//根据实际情况自己判断是否需要补充对导出文件的内容验证,此处暂时只判断文件是否存在
prev.setResponseData("下载成功","UTF-8");
//log.warn("下载成功");
}
else{
prev.setResponseData("下载失败","UTF-8");
//log.warn("下载失败");
}