# BeanShell 后置处理程序
String threadName = prev.getThreadName();
String sampleLabel = prev.getSampleLabel();
String method = prev.getHTTPMethod();
String url = prev.getUrlAsString();
String statusCode = prev.getResponseCode();
String requestBody = new String(ctx.getCurrentSampler().getArguments().getArgument(0).getValue());
String responseBody = prev.getResponseDataAsString();
log.info(threadName + " " + sampleLabel);
log.info("HTTP请求:" + method + " " + url);
log.info("请求体:" + requestBody);
log.info("HTTP响应码:" + statusCode);
log.info("响应体:" + responseBody);
2023-04-19 11:33:54,079 INFO o.a.j.u.BeanShellTestElement: setUp 线程组 1-1 HTTP请求 - quitTask
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: HTTP请求:POST https://xxxx.xxxx.xxxx/graphql/
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: 请求体:{"query":"\n mutation quitTask($slug: String!) {\n quitTask(taskSlug: $slug) {\n progressId\n ok\n deleted\n }\n}\n ","variables":{"slug":"xxxx"},"operationName":"quitTask"}
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: HTTP响应码:200
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: 响应体:{"errors":[{"message":"User is not in the task currently"}
# BeanShell 断言
String threadName = prev.getThreadName();
String sampleLabel = prev.getSampleLabel();
String method = prev.getHTTPMethod();
String url = prev.getUrlAsString();
String statusCode = prev.getResponseCode();
String requestBody = new String(ctx.getCurrentSampler().getArguments().getArgument(0).getValue());
String responseBody = prev.getResponseDataAsString();
String assertionMessage = prev.getFirstAssertionFailureMessage();
boolean isPassed = (assertionMessage == null);
log.info(threadName + " " + sampleLabel);
log.info("HTTP请求:" + method + " " + url);
log.info("请求体:" + requestBody);
log.info("HTTP响应码:" + statusCode);
log.info("响应体:" + responseBody);
log.info("断言结果: " + (isPassed ? "Passed" : "Failed"));
if (!isPassed) {
log.info("断言消息: " + assertionMessage);
}
2023-04-19 11:33:54,079 INFO o.a.j.u.BeanShellTestElement: setUp 线程组 1-1 HTTP请求 - quitTask
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: HTTP请求:POST https://xxxx.xxxx.xxxx/graphql/
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: 请求体:{"query":"\n mutation quitTask($slug: String!) {\n quitTask(taskSlug: $slug) {\n progressId\n ok\n deleted\n }\n}\n ","variables":{"slug":"xxxx"},"operationName":"quitTask"}
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: HTTP响应码:200
2023-04-19 11:33:54,080 INFO o.a.j.u.BeanShellTestElement: 响应体:{"errors":[{"message":"User is not in the task currently"}
2023-04-19 11:33:54,098 INFO o.a.j.u.BeanShellTestElement: 断言结果: Failed
2023-04-19 11:33:54,100 INFO o.a.j.u.BeanShellTestElement: 断言消息: Test failed: text expected to contain /"ok":true/
----原文----------------------------------------------------------------------------------------------
1. 在测试计划下(根节点)添加一个BeanShell后置处理器。
2. 在Script中写入以下语句。log.info()是写入日志,prev.getXXXX()方法是获取各项Jmeter的运行时的参数。
public void writeToLog(){
String logInfo = "\n";
//线程组名 + 采样器名称
logInfo = logInfo + prev.getThreadName() + " " + prev.getSampleLabel() + "\n";
//请求内容,如果仅需要url的话,可以使用prev.getUrlAsString()方法
logInfo = logInfo + prev.getSamplerData() + "\n";
//响应状态码
logInfo = logInfo + prev.getResponseCode() + "\n\n";
//响应内容
logInfo = logInfo + prev.getResponseDataAsString() + "\n";
//写入日志
log.info(logInfo);
}
writeToLog();
3. 运行你的脚本,点击右上角的警示图标就可以看到日志框里的日志信息了。主要打印了1.采样器名 2.请求 3.状态码 4.响应
4. 非GUI模式运行脚本,会在.jmx脚本文件所在路径生成Jmeter.log文件
5. Beanshell后置处理器中的语句,输出内容大致如下。
*该方法作为调试脚本和测试过程查看日志都起到很好的帮助。最主要是简洁,通用。相应的,性能测试不建议添加,会影响客户机的性能影响测试结果准确性。
6.更新一个目前一直在用的BeanShell断言,效果是不符合预期才写入日志。在跑性能时,也可以开启,方便查找原因。
*需要接口响应比较统一和规范
a. 全局后置处理器 获取接口响应errcode (如果接口不规范 则需要把正则放在每个接口下面,不能放在全局范围内)
例如:取出ResponseResult = 0
b. csv中获取断言
例如:取出Assertion = 0
c. 全局beanshell断言 将响应中errcode和断言做对比
//响应内容正则提取部分
String ResponseResult = vars.get("ResponseResult");
//断言
String Assertion = vars.get("Assertion");
//判断断言是否通过
if(ResponseResult.equals(Assertion) || ResponseResult.equals("Process Case")){
Failure = false;
//兼容其他并存的断言
FailureMessage = "接口响应:\r\n" + prev.getResponseDataAsString() + "\r\n";
}else{
Failure = true;
if (prev.getResponseDataAsString().length() < 255) {
FailureMessage = "接口响应:\r\n" + prev.getResponseDataAsString() + "\r\n";
}else{
FailureMessage = "接口响应片段:\r\n" + ResponseResult + "\r\n";
}
FailureMessage += "用例断言:\r\n" + Assertion;
String logInfo = "\n";
logInfo = logInfo + prev.getThreadName() + " " + prev.getSampleLabel() + "\n";
logInfo = logInfo + prev.getSamplerData() + "\n";
logInfo = logInfo + prev.getResponseCode() + "\n\n";
logInfo = logInfo + prev.getResponseDataAsString() + "\n";
log.info(logInfo);
}
*脚本中一些beanshell sampler不能被全局断言兼容,所以这类sampler添加一个后置处理器 填入 vars.put("ResponseResult","BeanShell"); 就可以在断言中pass了。
7. BeanShell常用内置类和方法:
log:写入信息到jmeber.log文件,例:log.info("这是一条日志");
ctx:该变量引用了当前线程的上下文
更多方法可参考:org.apache.jmeter.threads.JMeterContext
vars:操作jmeter变量
a) vars.get(String key)l:从jmeter中获得变量值
b) vars.put(String key,String value):数据存到jmeter变量中
更多方法可参考:org.apache.jmeter.threads.JMeterVariables
props:操作jmeter属性,使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。
a) props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义
b) props.put("PROP1","1234");
*props可用于线程组之间参数传递,即全局变量。 props.put("var_name","var_value");存 props.get("var_name");取
prev:获取前面的sample返回的信息:
a) getResponseDataAsString():获取响应信息
b) getResponseCode() :获取响应code
更多方法可参考:org.apache.jmeter.samplers.SampleResult
sampler:gives access to the current sampler (这个不太清楚,本人也没用过)