在我的 JMeter 场景中,我正在测试 SOAP 网络服务。我将初始请求发送到 webservice S1,然后使用它的响应来构建对 S2 的请求。
S1 的响应采用以下形式:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
    <s:response xmlns:s="http://custom.namespace.com/namespace">
    ...
        <s:responseDetails>
            <s:detail1>some info</s:detail>
            <s:detail2>another info<s:detail2>
            ...
        </s:responseDetails>
    </s:response>
</soap:Body>
</soap:Envelope>

我需要使用 <s:responseDetails> 中的所有内容来构建对 S2 的请求,但包装在不同的 xml 元素中:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://custom.namespace.com/namespace">
<soap:Body>
    <s:request>
        <s:details>
            <s:detail1>some info</s:detail>
            <s:detail2>another info<s:detail2>
            ...
        </s:details>
    </s:request>
</soap:Body>
</soap:Envelope>

注意请求中的元素 <s:details> 而不是 <s:responseDetails>

我开始使用 XPath 提取器,希望使用 XPath 表达式将 <s:responseDetails> 标记下的所有内容放入 JMeter 变量中:
  • //*[local-name()='responseDetails']/node() - 给我一组 JMeter 变量与 <s:responseDetails> 的不同子代,而我希望它们在一个变量中
  • //*[local-name()='responseDetails'] - 给了我整个节点 <s:responseDetails> 由于存在根标签 <s:responseDetails> ,我无法使用它,我需要用 <s:details>
  • 替换它

    <s:responseDetails> 中的所有内容都放入变量中的正确表达式是什么,以便我以后可以使用
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://custom.namespace.com/namespace">
    <soap:Body>
        <s:request>
            <s:details>
                ${details}
            </s:details>
        </s:request>
    </soap:Body>
    </soap:Envelope>
    

    或者也许有另一种方法可以解决我的问题?

    最佳答案

    请执行下列操作:

    1) 像您一样添加 XPath Extractor:

  • 引用名称:responseFragment
  • XPath 查询://s:response/s:responseDetails
  • 使用命名空间=true

  • 2) 添加一个 Beanshell 采样器:
    String fragment = vars.get("responseFragment");
    // Improve this replacement by regexp to avoid side effects
    String newFragment = fragment.replace("responseDetails","details");
     vars.put("modifiedFragment", newFragment);
    

    3)然后使用:${modifiedFragment}

    请注意,Beanshell 采样器会稍微降低 JMeter 的性能,但应该是合理的。

    请注意,您可以使用带有常规底层语言和外部文件中的脚本的 JSR 223 替换 Beanshell 采样器。

    使用 JMeter > 2.7 版本的性能将优于 beanshell 解决方案,因为新版本的 JMeter 引入了一种新的缓存机制,该机制将“编译”Groovy 脚本并使其几乎与 Java 类一样高效。

    截至 2012 年 9 月 3 日,此机制在 JMeter Nightly build 中可用。

    JMeter 测试计划示例:
        <?xml version="1.0" encoding="UTF-8"?>
    <jmeterTestPlan version="1.2" properties="2.3" jmeter="2.8-SNAPSHOT.20120903">
      <hashTree>
        <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
          <stringProp name="TestPlan.comments"></stringProp>
          <boolProp name="TestPlan.functional_mode">false</boolProp>
          <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
          <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="TestPlan.user_define_classpath"></stringProp>
        </TestPlan>
        <hashTree>
          <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
            <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
            <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" 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>
            <longProp name="ThreadGroup.start_time">1346673693000</longProp>
            <longProp name="ThreadGroup.end_time">1346673693000</longProp>
            <boolProp name="ThreadGroup.scheduler">false</boolProp>
            <stringProp name="ThreadGroup.duration"></stringProp>
            <stringProp name="ThreadGroup.delay"></stringProp>
          </ThreadGroup>
          <hashTree>
            <JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java Request" enabled="true">
              <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
                <collectionProp name="Arguments.arguments">
                  <elementProp name="Sleep_Time" elementType="Argument">
                    <stringProp name="Argument.name">Sleep_Time</stringProp>
                    <stringProp name="Argument.value">100</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="Sleep_Mask" elementType="Argument">
                    <stringProp name="Argument.name">Sleep_Mask</stringProp>
                    <stringProp name="Argument.value">0xFF</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="Label" elementType="Argument">
                    <stringProp name="Argument.name">Label</stringProp>
                    <stringProp name="Argument.value">OK</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="ResponseCode" elementType="Argument">
                    <stringProp name="Argument.name">ResponseCode</stringProp>
                    <stringProp name="Argument.value">200</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="ResponseMessage" elementType="Argument">
                    <stringProp name="Argument.name">ResponseMessage</stringProp>
                    <stringProp name="Argument.value">200</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="Status" elementType="Argument">
                    <stringProp name="Argument.name">Status</stringProp>
                    <stringProp name="Argument.value">OK</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="SamplerData" elementType="Argument">
                    <stringProp name="Argument.name">SamplerData</stringProp>
                    <stringProp name="Argument.value"></stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                  <elementProp name="ResultData" elementType="Argument">
                    <stringProp name="Argument.name">ResultData</stringProp>
                    <stringProp name="Argument.value">&lt;soap:Envelope xmlns:soap=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&gt; &lt;soap:Body&gt;     &lt;s:response xmlns:s=&quot;http://custom.namespace.com/namespace&quot;&gt;         &lt;s:responseDetails&gt;             &lt;s:detail1&gt;some info&lt;/s:detail1&gt;             &lt;s:detail2&gt;another info&lt;/s:detail2&gt;         &lt;/s:responseDetails&gt;     &lt;/s:response&gt; &lt;/soap:Body&gt; &lt;/soap:Envelope&gt;</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>
                </collectionProp>
              </elementProp>
              <stringProp name="classname">org.apache.jmeter.protocol.java.test.JavaTest</stringProp>
            </JavaSampler>
            <hashTree>
              <XPathExtractor guiclass="XPathExtractorGui" testclass="XPathExtractor" testname="XPath Extractor" enabled="true">
                <stringProp name="XPathExtractor.default"></stringProp>
                <stringProp name="XPathExtractor.refname">TOTO</stringProp>
                <stringProp name="XPathExtractor.xpathQuery">//s:response/s:responseDetails</stringProp>
                <boolProp name="XPathExtractor.validate">false</boolProp>
                <boolProp name="XPathExtractor.tolerant">false</boolProp>
                <boolProp name="XPathExtractor.namespace">true</boolProp>
                <boolProp name="XPathExtractor.whitespace">true</boolProp>
              </XPathExtractor>
              <hashTree/>
            </hashTree>
            <DebugSampler guiclass="TestBeanGUI" testclass="DebugSampler" testname="Debug Sampler" enabled="true">
              <boolProp name="displayJMeterProperties">false</boolProp>
              <boolProp name="displayJMeterVariables">true</boolProp>
              <boolProp name="displaySystemProperties">false</boolProp>
            </DebugSampler>
            <hashTree/>
            <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" 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>false</message>
                  <threadName>true</threadName>
                  <dataType>false</dataType>
                  <encoding>false</encoding>
                  <assertions>true</assertions>
                  <subresults>false</subresults>
                  <responseData>false</responseData>
                  <samplerData>false</samplerData>
                  <xml>false</xml>
                  <fieldNames>false</fieldNames>
                  <responseHeaders>false</responseHeaders>
                  <requestHeaders>false</requestHeaders>
                  <responseDataOnError>false</responseDataOnError>
                  <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
                  <assertionsResultsToSave>0</assertionsResultsToSave>
                  <bytes>true</bytes>
                  <hostname>true</hostname>
                  <threadCounts>true</threadCounts>
                  <sampleCount>true</sampleCount>
                </value>
              </objProp>
              <stringProp name="filename"></stringProp>
            </ResultCollector>
            <hashTree/>
          </hashTree>
        </hashTree>
      </hashTree>
    </jmeterTestPlan>
    

    其他方式:

    1) 像您一样添加 XPath Extractor:
  • 引用名称:responseFragment
  • XPath 查询://s:response/s:responseDetails/*
  • 使用命名空间=true

  • 2) 添加一个 Beanshell 采样器:
    int number = Integer.parseInt(vars.get("fullAnswer_matchNr"));
    StringBuilder builder = new StringBuilder();
    for(int i=0;i<number;i++) {
         builder.append(vars.get("fullAnswer_"+(i+1)));
    }
    vars.put("body", builder.toString());
    

    3)使用 body

    这个更干净一点,因为没有替代品

    关于xpath - 将没有节点本身的xml节点内容提取到jmeter中的变量中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12246055/

    10-09 18:54