Jmeter的Beanshell断言使用

698 阅读3分钟

JmeterBeanshell断言使用

  • jmeter如何将英文切换为中文

    • ${jmeter_home}/bin
      • 修改jmeter.properties
        • 新增一条记录:language=zh_CN
          • 注意:如果文件中已经存在language这个key,且该key处于放开的状态,那么需要在此上进行value的替换
  • jmeterbeanshelllog日志如何看?

    • ${jmeter_home}/bin下的jmeter.log
      • 通过tail命令就可以看到了beanshell中输出的日志
  • 解决痛点

    1. jmeter没有怎么使用过的人
    2. beanshell刚刚开始入门的同学
    3. 大多数文章处于断章取义吧,只给到部分截图,导致学习的人理解的不是很清晰;

实例场景如下

  • GET请求:http://localhost:9200/_cat/health?format=json

    • 看下最终的返回数据:

      [
        {
          "epoch" : "1648050037",
          "timestamp" : "15:40:37",
          "cluster" : "elasticsearch",
          "status" : "yellow",
          "node.total" : "1",
          "node.data" : "11",
          "shards" : "143",
          "pri" : "143",
          "relo" : "0",
          "init" : "0",
          "unassign" : "2",
          "pending_tasks" : "0",
          "max_task_wait_time" : "-",
          "active_shards_percent" : "98.6%"
        }
      ]
      
  • 需求是这样的:

    • 场景一
      • 通过Jmeter进行结果断言获取数组的大小,当size==1,证明该请求正确;
    • 场景二
      • 通过json path进行断言结果判断,当node.total==1,证明该请求正确

场景一

  1. 创建一个事件,如下图所示;

    image-20220323234539604
  2. json相关的包放到${jmeter_home}/lib目录下面,同时避免jmeter没有扫描到我们已经放置好的包,做到如下的配置,可最大避免找到问题的错误;

    1. 图一:当指定的包引入${jmeter_home}/lib目录下面,我们以fastjsonjson为例子,如图:

      image-20220323235221985
    2. 为了避免jmeter没有扫描到指定的包,同时我们创建的事件下引入lib目录,如图:

      image-20220323235837262
  3. 创建一个线程组,这里就不做演示了

  4. 我们创建一个请求,由于该请求带有验证,所以我们会通过如下步骤创建两个小的事件

    1. 添加一个请求,如图所示

      image-20220324000301173
    2. 添加一个http的认证,如图所示

      image-20220324000339754
  5. http请求目录下,分别添加,截图如下

    image-20220324000530445
    1. BeanShell断言,截图如下:

      image-20220324000603837
      • 由于接下来有两组测试

        • 判断结果size==1,脚本如下

          import com.alibaba.fastjson.JSON;
          import com.alibaba.fastjson.JSONArray;
          import com.alibaba.fastjson.JSONObject;
          
          
          String response = prev.getResponseDataAsString();
          JSONArray objects = JSON.parseArray(response);
          int length = objects.size();
          log.info("msg value:{}", length);
          if (length == 1) {
          	Failure = false;
          	FailureMessage = "交易成功!";
          	
          } else {
          	Failure = true;
          	FailureMessage = "交易失败!";
          }
          
        • 判断结果size==0,脚本如下

          import com.alibaba.fastjson.JSON;
          import com.alibaba.fastjson.JSONArray;
          import com.alibaba.fastjson.JSONObject;
          
          
          String response = prev.getResponseDataAsString();
          JSONArray objects = JSON.parseArray(response);
          int length = objects.size();
          log.info("msg value:{}", length);
          if (length == 0) {
          	Failure = false;
          	FailureMessage = "交易成功!";
          	
          } else {
          	Failure = true;
          	FailureMessage = "交易失败!";
          }
          
    2. 察看结果树

      image-20220324000809324
  6. 以上,完成了整个配置,可以看下最终结果,两组测试,分别会是一红一绿

    • 判断结果size==1:绿色,上图

      image-20220324001245769
    • 判断结果size==0:红色,上图

      image-20220324001130813
  7. 以上是整个fastjsonbeanshell断言的实现

场景二

这里我们使用json-path来进行断言实现,这里采用的json-pathmaven如下

<!-- https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path -->
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.7.0</version>
</dependency>
  • 这里说明一下,和[场景一](# 场景一)唯一的区别就在于第5步,所以这里我们只做对第5步骤的演示

  • 重点:这里必须引入json-path包,放置在jmeter下面,另外jmeter不支持直接引用·json-path的静态方法,所以只能绕弯路了,如果有人知道,也可以告诉我怎么在beanshell中引入

    1. 这里必须去实现一个class文件,小弟能力有限,不晓得怎么引入 .java文件,索引只能用反编译之后的class文件了

      
      import com.jayway.jsonpath.JsonPath;
      import com.jayway.jsonpath.internal.ParseContextImpl;
      
      public class JsonUtil {
      	
      	//public static void main(String[] args) {
      	//	String response = "[\n"
      	//			+ "  {\n"
      	//			+ "    \"epoch\" : \"1648050037\",\n"
      	//			+ "    \"timestamp\" : \"15:40:37\",\n"
      	//			+ "    \"cluster\" : \"elasticsearch\",\n"
      	//			+ "    \"status\" : \"yellow\",\n"
      	//			+ "    \"node.total\" : \"1\",\n"
      	//			+ "    \"node.data\" : \"11\",\n"
      	//			+ "    \"shards\" : \"143\",\n"
      	//			+ "    \"pri\" : \"143\",\n"
      	//			+ "    \"relo\" : \"0\",\n"
      	//			+ "    \"init\" : \"0\",\n"
      	//			+ "    \"unassign\" : \"2\",\n"
      	//			+ "    \"pending_tasks\" : \"0\",\n"
      	//			+ "    \"max_task_wait_time\" : \"-\",\n"
      	//			+ "    \"active_shards_percent\" : \"98.6%\"\n"
      	//			+ "  }\n"
      	//			+ "]";
      	//
      	//	ParseContextImpl parseContext = new ParseContextImpl();
      	//	Object read = JsonPath.read(response, "$.*.cluster");
      	//	//Object read1 = parseContext.parse(read).read("[0]");
      	//	//boolean elasticsearch = Objects.equals(read1, "elasticsearch");
      	//	//System.out.println(elasticsearch);
      	//	JsonUtil jsonUtil = new JsonUtil();
      	//	String data = jsonUtil.getData(response, "$.*.cluster");
      	//	String data1 = jsonUtil.getData(data, "[0]");
      	//	boolean elasticsearch = jsonUtil.equals(data1, "elasticsearch");
      	//	System.out.println(elasticsearch);
      	//
      	//
      	//}
      	
      	
      	public String getData(String json, String jsonPath) {
      		Object read = JsonPath.read(json, jsonPath);
      		
      		return read == null ? "" : read.toString();
      	}
      	
      	public boolean equals(Object obj1, Object obj2) {
      		return obj1.equals(obj2);
      	}
      }
      
    2. beanshell断言脚本如下:

      #我把JsonUtil.class放在D盘下面
      addClassPath("D:\\");
      import JsonUtil;
      String response = prev.getResponseDataAsString();
      log.info("msg value:{}", response);
      JsonUtil jsonUtil = new JsonUtil();
      String data = jsonUtil.getData(response, "$.*.cluster");
      String data1 = jsonUtil.getData(data,"[0]");
      boolean elasticsearch = jsonUtil.equals(data1, "elasticsearch");
      log.info("value:{}",elasticsearch);
      if (elasticsearch) {
      	Failure = false;
      	FailureMessage = "交易成功!";
      	
      } else {
      	Failure = true;
      	FailureMessage = "交易失败!";
      }
      
    • 这里执行结果就能发现结果是对的

    最后附上jmx内容,希望有人可以用到

    <?xml version="1.0" encoding="UTF-8"?>
    <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.3">
      <hashTree>
        <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="事件一(一级目录)" enabled="true">
          <stringProp name="TestPlan.comments">测试fastjson解析 最终结果判断 size==1 为正确</stringProp>
          <boolProp name="TestPlan.functional_mode">false</boolProp>
          <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
          <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
          <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="TestPlan.user_define_classpath">D:\software\apache-jmeter-5.4.3\lib,D:\software\apache-jmeter-5.4.3\lib\ext\JsonPath.jar</stringProp>
        </TestPlan>
        <hashTree>
          <SetupThreadGroup guiclass="SetupThreadGroupGui" testclass="SetupThreadGroup" testname="线程组(二级目录)" enabled="true">
            <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
            <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
              <boolProp name="LoopController.continue_forever">false</boolProp>
              <stringProp name="LoopController.loops">1</stringProp>
            </elementProp>
            <stringProp name="ThreadGroup.num_threads">1</stringProp>
            <stringProp name="ThreadGroup.ramp_time">1</stringProp>
            <boolProp name="ThreadGroup.scheduler">false</boolProp>
            <stringProp name="ThreadGroup.duration"></stringProp>
            <stringProp name="ThreadGroup.delay"></stringProp>
            <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
          </SetupThreadGroup>
          <hashTree>
            <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="请求(3级目录)" enabled="true">
              <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
                <collectionProp name="Arguments.arguments"/>
              </elementProp>
              <stringProp name="HTTPSampler.domain">locahost</stringProp>
              <stringProp name="HTTPSampler.port">9200</stringProp>
              <stringProp name="HTTPSampler.protocol"></stringProp>
              <stringProp name="HTTPSampler.contentEncoding"></stringProp>
              <stringProp name="HTTPSampler.path">_cat/health?format=json</stringProp>
              <stringProp name="HTTPSampler.method">GET</stringProp>
              <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
              <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
              <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
              <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
              <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
              <stringProp name="HTTPSampler.connect_timeout"></stringProp>
              <stringProp name="HTTPSampler.response_timeout"></stringProp>
            </HTTPSamplerProxy>
            <hashTree>
              <BeanShellAssertion guiclass="BeanShellAssertionGui" testclass="BeanShellAssertion" testname="BeanShell断言(四级目录)" enabled="true">
                <stringProp name="BeanShellAssertion.query">import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    
    
    String response = prev.getResponseDataAsString();
    JSONArray objects = JSON.parseArray(response);
    int length = objects.size();
    log.info(&quot;msg value:{}&quot;, length);
    if (length == 1) {
    	Failure = false;
    	FailureMessage = &quot;交易成功!&quot;;
    	
    } else {
    	Failure = true;
    	FailureMessage = &quot;交易失败!&quot;;
    }</stringProp>
                <stringProp name="BeanShellAssertion.filename"></stringProp>
                <stringProp name="BeanShellAssertion.parameters"></stringProp>
                <boolProp name="BeanShellAssertion.resetInterpreter">false</boolProp>
              </BeanShellAssertion>
              <hashTree/>
              <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="察看结果树(四级目录)" enabled="true">
                <boolProp name="ResultCollector.error_logging">false</boolProp>
                <objProp>
                  <name>saveConfig</name>
                  <value class="SampleSaveConfiguration">
                    <time>true</time>
                    <latency>true</latency>
                    <timestamp>true</timestamp>
                    <success>true</success>
                    <label>true</label>
                    <code>true</code>
                    <message>true</message>
                    <threadName>true</threadName>
                    <dataType>true</dataType>
                    <encoding>false</encoding>
                    <assertions>true</assertions>
                    <subresults>true</subresults>
                    <responseData>false</responseData>
                    <samplerData>false</samplerData>
                    <xml>false</xml>
                    <fieldNames>true</fieldNames>
                    <responseHeaders>false</responseHeaders>
                    <requestHeaders>false</requestHeaders>
                    <responseDataOnError>false</responseDataOnError>
                    <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
                    <assertionsResultsToSave>0</assertionsResultsToSave>
                    <bytes>true</bytes>
                    <sentBytes>true</sentBytes>
                    <url>true</url>
                    <threadCounts>true</threadCounts>
                    <idleTime>true</idleTime>
                    <connectTime>true</connectTime>
                  </value>
                </objProp>
                <stringProp name="filename"></stringProp>
              </ResultCollector>
              <hashTree/>
            </hashTree>
            <AuthManager guiclass="AuthPanel" testclass="AuthManager" testname="HTTP授权管理器(3级目录)" enabled="true">
              <collectionProp name="AuthManager.auth_list">
                <elementProp name="" elementType="Authorization">
                  <stringProp name="Authorization.url"></stringProp>
                  <stringProp name="Authorization.username">1111</stringProp>
                  <stringProp name="Authorization.password">111</stringProp>
                  <stringProp name="Authorization.domain"></stringProp>
                  <stringProp name="Authorization.realm"></stringProp>
                </elementProp>
              </collectionProp>
              <boolProp name="AuthManager.controlledByThreadGroup">false</boolProp>
            </AuthManager>
            <hashTree/>
          </hashTree>
          <SetupThreadGroup guiclass="SetupThreadGroupGui" testclass="SetupThreadGroup" testname="线程组(二级目录)" enabled="true">
            <stringProp name="TestPlan.comments">json-path使用</stringProp>
            <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
            <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
              <boolProp name="LoopController.continue_forever">false</boolProp>
              <stringProp name="LoopController.loops">1</stringProp>
            </elementProp>
            <stringProp name="ThreadGroup.num_threads">1</stringProp>
            <stringProp name="ThreadGroup.ramp_time">1</stringProp>
            <boolProp name="ThreadGroup.scheduler">false</boolProp>
            <stringProp name="ThreadGroup.duration"></stringProp>
            <stringProp name="ThreadGroup.delay"></stringProp>
            <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
          </SetupThreadGroup>
          <hashTree>
            <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="请求(3级目录)" enabled="true">
              <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
                <collectionProp name="Arguments.arguments"/>
              </elementProp>
              <stringProp name="HTTPSampler.domain">ip</stringProp>
              <stringProp name="HTTPSampler.port">9200</stringProp>
              <stringProp name="HTTPSampler.protocol"></stringProp>
              <stringProp name="HTTPSampler.contentEncoding"></stringProp>
              <stringProp name="HTTPSampler.path">_cat/health?format=json</stringProp>
              <stringProp name="HTTPSampler.method">GET</stringProp>
              <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
              <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
              <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
              <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
              <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
              <stringProp name="HTTPSampler.connect_timeout"></stringProp>
              <stringProp name="HTTPSampler.response_timeout"></stringProp>
            </HTTPSamplerProxy>
            <hashTree>
              <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="察看结果树(四级目录)" enabled="true">
                <boolProp name="ResultCollector.error_logging">false</boolProp>
                <objProp>
                  <name>saveConfig</name>
                  <value class="SampleSaveConfiguration">
                    <time>true</time>
                    <latency>true</latency>
                    <timestamp>true</timestamp>
                    <success>true</success>
                    <label>true</label>
                    <code>true</code>
                    <message>true</message>
                    <threadName>true</threadName>
                    <dataType>true</dataType>
                    <encoding>false</encoding>
                    <assertions>true</assertions>
                    <subresults>true</subresults>
                    <responseData>false</responseData>
                    <samplerData>false</samplerData>
                    <xml>false</xml>
                    <fieldNames>true</fieldNames>
                    <responseHeaders>false</responseHeaders>
                    <requestHeaders>false</requestHeaders>
                    <responseDataOnError>false</responseDataOnError>
                    <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
                    <assertionsResultsToSave>0</assertionsResultsToSave>
                    <bytes>true</bytes>
                    <sentBytes>true</sentBytes>
                    <url>true</url>
                    <threadCounts>true</threadCounts>
                    <idleTime>true</idleTime>
                    <connectTime>true</connectTime>
                  </value>
                </objProp>
                <stringProp name="filename"></stringProp>
              </ResultCollector>
              <hashTree/>
              <BeanShellAssertion guiclass="BeanShellAssertionGui" testclass="BeanShellAssertion" testname="BeanShell断言(四级目录)" enabled="true">
                <stringProp name="BeanShellAssertion.query">addClassPath(&quot;D:\\&quot;);
    import JsonUtil;
    String response = prev.getResponseDataAsString();
    log.info(&quot;msg value:{}&quot;, response);
    JsonUtil jsonUtil = new JsonUtil();
    String data = jsonUtil.getData(response, &quot;$.*.cluster&quot;);
    String data1 = jsonUtil.getData(data,&quot;[0]&quot;);
    boolean elasticsearch = jsonUtil.equals(data1, &quot;elasticsearch&quot;);
    log.info(&quot;value:{}&quot;,elasticsearch);
    if (elasticsearch) {
    	Failure = false;
    	FailureMessage = &quot;交易成功!&quot;;
    	
    } else {
    	Failure = true;
    	FailureMessage = &quot;交易失败!&quot;;
    }</stringProp>
                <stringProp name="BeanShellAssertion.filename"></stringProp>
                <stringProp name="BeanShellAssertion.parameters"></stringProp>
                <boolProp name="BeanShellAssertion.resetInterpreter">false</boolProp>
              </BeanShellAssertion>
              <hashTree/>
            </hashTree>
            <AuthManager guiclass="AuthPanel" testclass="AuthManager" testname="HTTP授权管理器(3级目录)" enabled="true">
              <collectionProp name="AuthManager.auth_list">
                <elementProp name="" elementType="Authorization">
                  <stringProp name="Authorization.url"></stringProp>
                  <stringProp name="Authorization.username">1111</stringProp>
                  <stringProp name="Authorization.password">1111</stringProp>
                  <stringProp name="Authorization.domain"></stringProp>
                  <stringProp name="Authorization.realm"></stringProp>
                </elementProp>
              </collectionProp>
              <boolProp name="AuthManager.controlledByThreadGroup">false</boolProp>
            </AuthManager>
            <hashTree/>
          </hashTree>
        </hashTree>
      </hashTree>
    </jmeterTestPlan>