Jmeter + selenium + ant 接口自动化并生成报告

时间:2024-03-05 21:57:10

一、数据准备

这里不详细介绍Jmeter的使用方法,重点介绍jmeter与ant的整合

1、添加测试计划-->执行测试用例-->成功后文件另存为.jmx文件

2、在jmeter的目录下新建TestCase文件夹

 

 

3、将该.jmx文件存放至该文件夹下

 

二、工具准备

1、ant的下载地址为: http://ant.apache.org/

2、添加环境变量:新建系统变量ANT_HOME

 

在path环境变量中加入%ANT_HOME%\bin(注意前面分号)

 

3、确认ant环境配置,打开cmd命令提示符,输入ant -v,出现如下图说明环境配置OK

 

三、整合

1、把Jmeter根目录\extras下的ant-jmeter-xxx.jar拷贝到ant的根目录\lib下

 

To

 

2、将jmeter的根目录\extras下的build.xml文件复制一份到新建的文件TestCase里去

 

四、修改配置

1、修改build.xml文件如下

 2、修改jmeter.properties配置文件

jmeter.save.saveservice.output_format=csv   

改为

jmeter.save.saveservice.output_format=xml

五、生成报告

1、方法一:打开cmd命令提示符,进入build.xml所在目录的根目录,执行ant命令,一份简单的报告就这样生成了。

2、方法二:在build.xml同级目录创建一个build.bat文件,文件内容为ant,然后双击build.bat,jmeter脚本即可自动运行并在指定位置生成对应的测试报告

 

六、优化报告

上述生成的报告看起来成功,但如出错很难从报告上定位问题,并定位问题在哪里

优化过程:

1、jmeter默认的报告展示信息比较少,其实是由.jtl格式转化为.html格式的报告过程中style文件起了很关键的作用。这里介绍另一种style文件的使用方法:

A) 下载style文件:jmeter.results.shanhe.me.xsl ,该文件可自行网上搜索;

作者使用的是 hph_report.xsl,将上述 build.xml 中 report sytle 值修改为此文件名

B)  把下载的文件放到jmeter的extras目录下 ;

2、修改JMeter.properties文件如下部分,我这里都修改成true,这样执行完脚本后

就会保存这些结果到.jtl文件

 1 jmeter.save.saveservice.response_code=true
 2 # response_data is not currently supported for CSV output
 3 jmeter.save.saveservice.response_data=true
 4 # Save ResponseData for failed samples
 5 jmeter.save.saveservice.response_data.on_error=false
 6 jmeter.save.saveservice.response_message=true
 7 jmeter.save.saveservice.successful=true
 8 jmeter.save.saveservice.thread_name=true
 9 jmeter.save.saveservice.time=true
10 jmeter.save.saveservice.subresults=true
11 jmeter.save.saveservice.assertions=true
12 #jmeter.save.saveservice.latency=true
13 # Only available with HttpClient4
14 jmeter.save.saveservice.connect_time=true
15 jmeter.save.saveservice.samplerData=true
16 jmeter.save.saveservice.responseHeaders=true
17 jmeter.save.saveservice.requestHeaders=true
18 jmeter.save.saveservice.encoding=true
19 #jmeter.save.saveservice.bytes=true
20 # Only available with HttpClient4
21 jmeter.save.saveservice.sent_bytes=true
22 jmeter.save.saveservice.url=true
23 jmeter.save.saveservice.filename=true
24 jmeter.save.saveservice.hostname=true
25 jmeter.save.saveservice.thread_counts=true
26 jmeter.save.saveservice.sample_count=true
27 jmeter.save.saveservice.idle_time=true
jmeter.property

 

3、修改build.xml文件,附上自己的原文件,修改一下自己的 jmeter 环境变量地址

<?xml version="1.0" encoding="UTF-8"?>
<!--
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at
    
       http://www.apache.org/licenses/LICENSE-2.0
    
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-->
<project name="ant-jmeter" default="all" basedir=".">
    <tstamp>
        <format property="time" pattern="yyyy/MM/dd HH:mm" />
        <format property="timelog" pattern="yyyyMMddHHmm" />
        <format property="timeyj" pattern="MMddyyyHHmm" />
    </tstamp>

    <description>

        Sample build file for use with ant-jmeter.jar
        See http://www.programmerplanet.org/pages/projects/jmeter-ant-task.php

    To run a test and create the output report:
        ant -Dtest=script

    To run a test only:
        ant -Dtest=script run

    To run report on existing test output
        ant -Dtest=script report

    The "script" parameter is the name of the script without the .jmx suffix.

    Additional options:
        -Dshow-data=y - include response data in Failure Details
        -Dtestpath=xyz - path to test file(s) (default user.dir).
                         N.B. Ant interprets relative paths against the build file
        -Djmeter.home=.. - path to JMeter home directory (defaults to parent of this build file)
        -Dreport.title="My Report" - title for html report (default is \'Load Test Results\')
    </description>
    <property name="jmeter.home" value="这里为 jmeter环境变量目录"/>
    <property name="testpath" value="${jmeter.home}/TestCase"/>
    <property name="jmeter.result.jtl.dir" value="${jmeter.home}/TestCase/report/jtl"/>
    <property name="jmeter.result.html.dir" value="${jmeter.home}/TestCase/report/html"/>
    <property name="jmeter.result.jtlName" value="${jmeter.result.jtl.dir}/${ReportName}${timelog}.jtl"/>
    <property name="jmeter.result.htmlName" value="${jmeter.result.html.dir}/${ReportName}${timelog}.html"/>
    <property name="jmeter.result.htmlNameyj" value="${jmeter.result.html.dir}/${ReportName}${timeyj}.html"/>
    <property name="lib.dir" value="${jmeter.home}/lib"/>
    <property name="ReportName" value="TestReport"/>
    
    <!-- Name of test (without .jmx) -->
    <property name="test" value="这里填写 jmeter 脚本名称,注意不含.jmx"/>
    
    <!-- Should report include response data for failures? -->
    <property name="show-data" value="n"/>

    <property name="format" value="2.1"/>
    
    <condition property="style_version" value="_21">
        <equals arg1="${format}" arg2="2.1"/>
    </condition>

    <condition property="funcMode">
        <equals arg1="${show-data}" arg2="y"/>
    </condition>
    
    <condition property="funcMode" value="false">
      <not>
        <equals arg1="${show-data}" arg2="y"/>
      </not>
    </condition>

    <!-- Allow jar to be picked up locally (jmeter 相对应 ant-jmeter-1.1.1.jar 包存放地址及包名设置)-->
    <path id="jmeter.classpath">
        <fileset dir="${jmeter.home}/extras">
          <include name="ant-jmeter*.jar"/>
        </fileset>
    </path>

    <taskdef
        name="jmeter"
        classpathref="jmeter.classpath"

        classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"/>
    <!--运行的顺序,先 run test 后 report -->
    <target name="all" depends="run,report"/> 

    <target name="run">
        <echo>funcMode = ${funcMode}</echo>
        <delete file="${jmeter.result.html.dir}/${test}.html"/>
        <jmeter
            jmeterhome="${jmeter.home}"
            testplan ="${testpath}/${test}.jmx"   
            resultlog="${jmeter.result.jtl.dir}/${test}.jtl">
        <!--
            <jvmarg value="-Xincgc"/>
            <jvmarg value="-Xmx128m"/>
            <jvmarg value="-Dproperty=value"/>
            <jmeterarg value="-qextra.properties"/>
        -->
            <!-- Force suitable defaults jmeter相对应配置要改为 true-->
                <property name="jmeter.save.saveservice.response_data" value="true"/>
                <property name="jmeter.save.saveservice.samplerData" value="true"/>
                <property name="jmeter.save.saveservice.responseHeaders" value="true"/>
                <property name="jmeter.save.saveservice.requestHeaders" value="true"/>
                <property name="jmeter.save.saveservice.encoding" value="true"/>
                <property name="jmeter.save.saveservice.url" value="true"/>
                <property name="jmeter.save.saveservice.filename" value="true"/>
                <property name="jmeter.save.saveservice.hostname" value="true"/>
                <property name="jmeter.save.saveservice.thread_counts" value="true"/>
                <property name="jmeter.save.saveservice.sample_count" value="true"/>
                <property name="jmeter.save.saveservice.idle_time" value="true"/>
                <property name="jmeter.save.saveservice.output_format" value="xml"/>
                <property name="jmeter.save.saveservice.assertion_results" value="all"/>
                <property name="jmeter.save.saveservice.bytes" value="true"/>
                <property name="file_format.testlog" value="${format}"/>
                <property name="jmeter.save.saveservice.response_data.on_error" value="${funcMode}"/>
        </jmeter>
    </target>

    <property name="lib.dir" value="${jmeter.home}/lib"/>

    <!-- Use xalan copy from JMeter lib directory to ensure consistent processing with Java 1.4+ -->
    <path id="xslt.classpath">
        <fileset dir="${lib.dir}" includes="xalan*.jar"/>
        <fileset dir="${lib.dir}" includes="serializer*.jar"/>
    </path>

    <target name="report" depends="xslt-report,copy-images">
        <echo>Report generated at ${report.datestamp}</echo>
    </target>
    <!-- 报告样式设置 -->
    <target name="xslt-report" depends="_message_xalan">
        <tstamp><format property="report.datestamp" pattern="yyyy/MM/dd HH:mm"/></tstamp>
        <xslt
            classpathref="xslt.classpath"
            force="true"
            in="${jmeter.result.jtl.dir}/${test}.jtl"
            out="${jmeter.result.html.dir}/${test}.html"
            style="${jmeter.home}/extras/jmeter-results-hph_report.xsl">
            <param name="showData" expression="${show-data}"/>
            <param name="titleReport" expression="${report.title}"/>
            <param name="dateReport" expression="${report.datestamp}"/>
        </xslt>
    </target>

    <!-- Copy report images if needed -->
    <target name="copy-images" depends="verify-images" unless="samepath">
        <copy file="${basedir}/expand.png" tofile="${testpath}/expand.png"/>
        <copy file="${basedir}/collapse.png" tofile="${testpath}/collapse.png"/>
    </target>

    <target name="verify-images">
        <condition property="samepath">
                <equals arg1="${testpath}" arg2="${basedir}" />
        </condition>
    </target>

    <!-- Check that the xalan libraries are present -->
    <condition property="xalan.present">
          <and>
              <!-- No need to check all jars; just check a few -->
            <available classpathref="xslt.classpath" classname="org.apache.xalan.processor.TransformerFactoryImpl"/>
            <available classpathref="xslt.classpath" classname="org.apache.xml.serializer.ExtendedContentHandler"/>
          </and>
    </condition>

    <target name="_message_xalan" unless="xalan.present">
          <echo>Cannot find all xalan and/or serialiser jars</echo>
        <echo>The XSLT formatting may not work correctly.</echo>
        <echo>Check you have xalan and serializer jars in ${lib.dir}</echo>
    </target>


</project>
build.xml

 

 

 

 将此文件覆盖原jmeter-result-report.xsl

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  3     <xsl:output method="html" indent="no" encoding="UTF-8" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" doctype-system="http://www.w3.org/TR/html4/loose.dtd"/>
  4     <xsl:strip-space elements="*"/>
  5     <xsl:template match="/testResults">
  6         <html lang="en">
  7         <head>
  8             <meta name="Author" content="shanhe.me"/>
  9             <title>JMeter Test Results</title>
 10             <style type="text/css"><![CDATA[
 11             
 12                 * { margin: 0; padding: 0 }
 13                 html, body { width: 100%; height: 100%; background: #b4b4b4; font-size: 12px }
 14                 table { border: none; border-collapse: collapse; table-layout: fixed }
 15                 td { vertical-align: baseline; font-size: 12px }
 16                 #left-panel { position: absolute; left: 0; top: 0; bottom: 0; width: 300px; overflow: auto; background: #dee4ea }
 17                 #left-panel li.navigation { font-weight: bold; cursor: default; color: #9da8b2; line-height: 18px; background-position: 12px 5px; background-repeat: no-repeat; padding: 0 0 0 25px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAICAYAAAArzdW1AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBQqGbO7BEcAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAKRJREFUGNN1zM0KgkAYheF3RvtXSsGyWhRNaILS7bdt11W0KgJvoPwZp0UlBPUtz3nOJw7Hk7necv5dOA2Qaazo2vZP0LEt9olCVtqQROufKNmuqBuBNAYW4QzXGX6B0bDPcjGnMQYJ8Cg12U59oSzaUJQa4IUAXMclDHwAAn/MxPMw765FZd2QRgopBWmsKCrdfhXnS/4ZYElBXdyxewN008Y8AephLAkqz613AAAAAElFTkSuQmCC) }
 18                 #left-panel li.success { color: #565b60 }
 19                 #left-panel li.failure { color: red }
 20                 #left-panel li { list-style: none; color: black; cursor: pointer }
 21                 #left-panel li.selected { background-repeat: repeat-x; color: white; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAUCAYAAABMDlehAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBQxLTs5O2gAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAEdJREFUCNc1y7ERgEAMA0GNUhIyGqM2uqKgtyWZhE9v53A/7/A6D7BkMDNgy2AroB2wHTCZv5UMOgFLG1bvd7XBckBlwCXjA5wMOF5iOX/MAAAAAElFTkSuQmCC) }
 22                 #left-panel div { line-height: 25px; background-position: 25px 3px; background-repeat: no-repeat; padding: 0 0 0 45px }
 23                 #left-panel div.success { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAOCAYAAADwikbvAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBULEEc6wzcAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAiNJREFUKM99kktIVGEYhp/jzJl08lI6logp2Y2EFkbtaqlFROsWrlq4ioJWQRs37VoUVItWkYEVRGSBlhleCpywDEWxTEuxcURTZ6YzxzP/5WshCOHUt36f93kXnyMi5Lsnb4clI4s4fhkXzp5w8mWcfHBvfEpUxVdCUUU6lUPNHuD86cYtBQX5GhPrM7hRg7GaSDRg2vuUd90WuOPVsOyqy6FFo2yOQHlU1S9z9dZT+S/8I7GCLlkAN4eyAf56mnT6Fy1HLnGuuYa++MS/4e74qMRqfXLaJ9BpfnsrLC0m2BYuoqwUbj/+274JD43OEqmexwvW8NUKXnaZtVSS1pNtAAyOvyC6v48HnUNb4Z7PH8UtTlIQWA5tb2RhYY7kz3l2FleytJYg/qWb8t2KZ/0PN+1hgI6uEUr2jpHKpGlquExVaS0VbjUZL7WxaqIXK6ADQ0n9GNfv9XCttWnD/O57t0TKFklnF3g5fJ/seoaa2D4O1x0F4PlgO9oIftbgFgYMfLgjACGqj0vlsddoUnj+Kt/mxunq72RP+UGqYjWMTA7R+b6dUCSEGEF5hoJQip6BaFs4HJtCyRrKs6wHCovDip/kys0WWpovMpOYBCtoT2N9B5uzWG0Zid8gnFrVFEQDtBaUrxEgXBimaEeER2/uIiK4roPOaMRYjBKsFly3fOO3G06dETGCWIsYjckprMphtEKMAQtgsMYi1mJMQHJ6xvkDKQoyphCzkl0AAAAASUVORK5CYII=) }
 24                 #left-panel div.failure { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAOCAYAAADwikbvAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBUJOEC5CU8AAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAeVJREFUKM+NkDtok2EUhp8vl9ZLo/EyKI6KFgqCKC4OClrBWUQEcRRx1cGpk3WyInWrgoMZKkW8thYaEYQ0i7WC2ngrNDTERHJvkv/L/3//dxwc7F8jeOAsh/c973OOEhG61aPnaen7maXYt4MLZ4+pbppQt+F06jNH3QWOb8pxUs+SmJzjv83hxY8SVy3wNdtVneiHqe54IhLoB4/TUkyMyOrKj5yXoVtPZK02kLyYK7OnlqFWzgcCGtUC/YUJ3n5a/jd28tU7ORTN0myUA6Jms8bpWIa798elqzn1fokjThrpVBC3ETzNbYAuca59j/Hp+b/N869Tsk8tgVMCXQk+RlfQuk1/tMLMwzsSMCcm5zjhvoR2AdpF0GuwO4aqttS05ZSbZHhsBoAIwI83Cdkd/460XDAOG02d24MxvlR8dsUUh3f2UHaEtgdbWCHz4oZwcVCp66PP5FLhKjEc8DXaCMsNy8DYn/SnZ+L0hhWOb/F8yLs9fDtwk8j+VpqwrlC34PrgGEu2bhlYhZ1b8dncq3AMeBaUr/k6NUyk4ChKzu+N2hc6Bqody+WDG8g2fLatD7F3axjPgmvAtYJvIbouhhIRrl0ZktnkBGIt1gqeMXQ8D2MMiCIUCqFEsFhEQMSykCuqX0MzLAUJTzRsAAAAAElFTkSuQmCC) }
 25                 #left-panel div.detail { display: none }
 26                 #right-panel { position: absolute; right: 0; top: 0; bottom: 0; left: 301px; overflow: auto; background: white }
 27                 #right-panel .group { font-size: 12px; font-weight: bold; line-height: 20px; padding: 0 0 2px 18px; counter-reset: assertion; background-repeat: repeat-x; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAQCAYAAADXnxW3AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBUkDq8pxjkAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAADdJREFUCNdVxrERwDAMAzGK0v47eS6Z927SpMFBAAbkvSvnRk5+7K5cVfLMyN39bWakJAjA5xw9R94jN3tVhVEAAAAASUVORK5CYII=) }
 28                 #right-panel .zebra { background-repeat: repeat; padding: 0 0 20px 18px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAmCAYAAAAFvPEHAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBYWFlNztEcAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAABdJREFUCNdjYKAtePv5338mBgYGBpoQAGy1BAJlb/y6AAAAAElFTkSuQmCC) }
 29                 #right-panel .data { line-height: 24px; white-space: nowrap}
 30                 #right-panel pre.data { white-space: pre-line}
 31                 #right-panel tbody.failure { color: red }
 32                 #right-panel td.key { min-width: 108px }
 33                 #right-panel td.delimiter { min-width: 18px }
 34                 #right-panel td.assertion:before { counter-increment: assertion; content: counter(assertion) ". " }
 35                 #right-panel td.assertion { color: black }
 36                 #right-panel .trail { border-top: 1px solid #b4b4b4 }
 37                 
 38             ]]></style>
 39             <script type="text/javascript"><![CDATA[
 40             
 41                 var onclick_li = (function() {
 42                     var last_selected = null;
 43                     return function(li) {
 44                         if( last_selected == li )
 45                             return;
 46                         if( last_selected )
 47                             last_selected.className = "";
 48                         last_selected = li;
 49                         last_selected.className = "selected";
 50                         var detail = li.querySelector(\'div.detail\');
 51                         // deleted
 52                         //document.getElementById("right-panel").innerHTML = last_selected.firstChild.nextSibling.innerHTML;
 53                         // add
 54                         document.getElementById("right-panel").innerHTML = detail.innerHTML;
 55                         return false;
 56                     };
 57                 })();
 58                 
 59                 var patch_timestamp = function() {
 60                     var spans = document.getElementsByTagName("span");
 61                     var len = spans.length;
 62                     for( var i = 0; i < len; ++i ) {
 63                         var span = spans[i];
 64                         if( "patch_timestamp" == span.className )
 65                             span.innerHTML = new Date( parseInt( span.innerHTML ) );
 66                     }
 67                 };
 68                 
 69                 var patch_navigation_class = (function() {
 70                 
 71                     var set_class = function(el, flag) {
 72                         if(el) {
 73                             el.className += flag ? " success" : " failure";
 74                         }
 75                     };
 76                 
 77                     var traverse = function(el, group_el, flag) {
 78                         while(1) {
 79                             if(el) {
 80                                 if(el.className == \'navigation\') {
 81                                     set_class(group_el, flag);
 82                                     group_el = el;
 83                                     flag = true;
 84                                 } else {
 85                                     var o = el.firstChild;
 86                                     o = o ? o.className : null;
 87                                     flag = flag ? (o == \'success\') : false;
 88                                 }
 89                                 el = el.nextSibling;
 90                             } else {
 91                                 set_class(group_el, flag);
 92                                 break;
 93                             }
 94                         }
 95                     };
 96                     
 97                     return function() {
 98                         var o = document.getElementById("result-list");
 99                         o = o ? o.firstChild : null;
100                         if(o)
101                             traverse(o, null, true);
102                     };
103                 })();
104         
105                 window.onload = function() {
106                     patch_timestamp();
107                     patch_navigation_class();
108                     // deleted
109                     //var o = document.getElementById("result-list");
110                     //o = o ? o.firstChild : null;
111                     //o = o ? o.nextSibling : null;
112                     // add
113                     var o = document.querySelector(\'li[onclick]\'); 
114                     if(o)
115                         onclick_li(o);
116                 };
117         
118             ]]></script>
119         </head>
120         <body>
121             <div id="left-panel">
122                 <ol id="result-list">
123                  <li onclick="return onclick_li(this);">
124                       <div>测试结果概况</div>
125                       <div class="detail">
126                                 <div class="zebra">
127                         <xsl:call-template name="summary" />
128                              </div>
129                              <div class="zebra">
130                                  <xsl:call-template name="pagelist" />
131                              </div>
132                      </div>
133                      </li> 
134                     <xsl:for-each select="*">
135                         <!-- group with the previous sibling -->
136                         <!--
137                         <xsl:if test="position() = 1 or @tn != preceding-sibling::*[1]/@tn">
138                             <li class="navigation">Thread: <xsl:value-of select="@tn"/></li>
139                         </xsl:if>
140                         -->
141                         <li onclick="return onclick_li(this);">
142                             <div>
143                                 <xsl:attribute name="class">
144                                     <xsl:choose>
145                                         <xsl:when test="@s = \'true\'">success</xsl:when>
146                                         <xsl:otherwise>failure</xsl:otherwise>
147                                     </xsl:choose>
148                                 </xsl:attribute>
149                                 <xsl:value-of select="@lb"/>
150                             </div><div class="detail">
151                                 <div class="group">Sampler</div>
152                                 <div class="zebra">
153                                     <table>
154                                         <tr><td class="data key">Thread Name</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@tn"/></td></tr>
155                                         <tr><td class="data key">Timestamp</td><td class="data delimiter">:</td><td class="data"><span class="patch_timestamp"><xsl:value-of select="@ts"/></span></td></tr>
156                                         <tr><td class="data key">Time</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@t"/> ms</td></tr>
157                                         <tr><td class="data key">Latency</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@lt"/> ms</td></tr>
158                                         <tr><td class="data key">Bytes</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@by"/></td></tr>
159                                         <tr><td class="data key">Sample Count</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@sc"/></td></tr>
160                                         <tr><td class="data key">Error Count</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@ec"/></td></tr>
161                                         <tr><td class="data key">Response Code</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@rc"/></td></tr>
162                                         <tr><td class="data key">Response Message</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="@rm"/></td></tr>
163                                     </table>
164                                 </div>
165                                 <div class="trail"></div>
166                                 <xsl:if test="count(assertionResult) &gt; 0">
167                                     <div class="group">Assertion</div>
168                                     <div class="zebra">
169                                         <table>
170                                             <xsl:for-each select="assertionResult">
171                                                 <tbody>
172                                                     <xsl:attribute name="class">
173                                                         <xsl:choose>
174                                                             <xsl:when test="failure = \'true\'">failure</xsl:when>
175                                                             <xsl:when test="error = \'true\'">failure</xsl:when>
176                                                         </xsl:choose>
177                                                     </xsl:attribute>
178                                                     <tr><td class="data assertion" colspan="3"><xsl:value-of select="name"/></td></tr>
179                                                     <tr><td class="data key">Failure</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="failure"/></td></tr>
180                                                     <tr><td class="data key">Error</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="error"/></td></tr>
181                                                     <tr><td class="data key">Failure Message</td><td class="data delimiter">:</td><td class="data"><xsl:value-of select="failureMessage"/></td></tr>
182                                                 </tbody>
183                                             </xsl:for-each>
184                                         </table>
185                                     </div>
186                                     <div class="trail"></div>
187                                 </xsl:if>
188                                 <div class="group">Request</div>
189                                 <div class="zebra">
190                                     <table>
191                                         <tr><td class="data key">Method/Url</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="method"/><xsl:text> </xsl:text><xsl:value-of select="java.net.URL"/></pre></td></tr>
192                                         <tr><td class="data key">Query String</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="queryString"/></pre></td></tr>
193                                         <tr><td class="data key">Cookies</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="cookies"/></pre></td></tr>
194                                         <tr><td class="data key">Request Headers</td><td class="data delimiter">:</td><td class="data" ><pre class="data"><xsl:value-of select="requestHeader"/></pre></td></tr>
195                                     </table>
196                                 </div>
197                                 <div class="trail"></div>
198                                 <div class="group">Response</div>
199                                 <div class="zebra">
200                                     <table>
201                                         <tr><td class="data key">Response Headers</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="responseHeader"/></pre></td></tr>
202                                         <tr><td class="data key">Response Data</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="responseData"/></pre></td></tr>
203                                         <tr><td class="data key">Response File</td><td class="data delimiter">:</td><td class="data"><pre class="data"><xsl:value-of select="responseFile"/></pre></td></tr>
204                                     </table>
205                                 </div>
206                                 <div class="trail"></div>
207                             </div>
208                         </li>
209                     </xsl:for-each>
210                 </ol>
211             </div>
212             <div id="right-panel"></div>
213             <script>
214         Spliter = function (objLeft, objRight) {
215             this.flag = false;
216             var ele = document.createElement(\'div\');
217             document.body.append(ele);
218             ele.style.height = "100%";
219             ele.style.position = "absolute";
220             ele.style.width = "5px";
221             ele.style.left = objLeft.offsetWidth - 2 + "px";
222             ele.style.backgroundColor = "gray";
223             ele.style.opacity = 0;
224 
225             this.ele = ele
226             this.objLeft = objLeft;
227             this.objRight = objRight;
228             this.ele.style.cursor = "w-resize"; //设置鼠标样式
229             this.up = function (event) {
230                 if (this.flag) {
231                     if (this.ele.releaseCapture) {
232                         this.ele.releaseCapture();
233                     }
234                     else {
235                         document.removeEventListener(\'mouseup\', this.up.bind(this), true);
236                         document.removeEventListener(\'mousemove\', this.move.bind(this), true);
237                         event.preventDefault();
238                     }
239 
240                     this.ele.style.opacity = 0;
241                     this.flag = false;
242                 }
243             };
244             this.down = function (event) {
245                 if (!this.flag) {
246                     if (this.ele.setCapture)
247                         this.ele.setCapture();
248                     else {
249                         document.addEventListener(\'mouseup\', this.up.bind(this), true);
250                         document.addEventListener(\'mousemove\', this.move.bind(this), true);
251                         event.preventDefault();
252                     }
253 
254                     this.ele.style.opacity = 0.5;
255                     this.flag = true;
256                 }
257             };
258             this.move = function (event) {
259 
260                 if (this.flag) {
261                     var minWidth = 10;
262                     var left = Math.max(minWidth, event.clientX);
263                     this.objLeft.style.width = left + "px";
264                     this.objRight.style.left = left + "px";
265                     this.ele.style.left = left - 2 + "px";
266                     if (!this.ele.releaseCapture) {
267                         event.preventDefault();
268                     }
269                 }
270             }
271             var t = this;
272             this.ele.onmousedown = function () {
273                 t.down(event);
274             }
275 
276             this.ele.onmouseup = function () {
277                 t.up(event);
278             }
279 
280             this.ele.onmousemove = function () {
281                 t.move(event);
282             }
283             return this;
284         }
285 
286         new Spliter(document.getElementById("left-panel"), document.getElementById("right-panel"));
287         </script>
288         </body>
289         
290         </html>
291     </xsl:template>
292 <xsl:template name="summary">
293     <div class="group">Summary</div>
294     <table align="center" class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
295         <tr valign="top">
296             <th>请求总数</th>
297             <th>异常数</th>
298             <th>成功率</th>
299             <th>平均消耗时间</th>
300             <th>最小消耗时间</th>
301             <th>最大消耗时间</th>
302         </tr>
303         <tr valign="top">
304             <xsl:variable name="allCount" select="count(/testResults/*)" />
305             <xsl:variable name="allFailureCount" select="count(/testResults/*[attribute::s=\'false\'])" />
306             <xsl:variable name="allSuccessCount" select="count(/testResults/*[attribute::s=\'true\'])" />
307             <xsl:variable name="allSuccessPercent" select="$allSuccessCount div $allCount" />
308             <xsl:variable name="allTotalTime" select="sum(/testResults/*/@t)" />
309             <xsl:variable name="allAverageTime" select="$allTotalTime div $allCount" />
310             <xsl:variable name="allMinTime">
311                 <xsl:call-template name="min">
312                     <xsl:with-param name="nodes" select="/testResults/*/@t" />
313                 </xsl:call-template>
314             </xsl:variable>
315             <xsl:variable name="allMaxTime">
316                 <xsl:call-template name="max">
317                     <xsl:with-param name="nodes" select="/testResults/*/@t" />
318                 </xsl:call-template>
319             </xsl:variable>
320             <xsl:attribute name="class">
321                 <xsl:choose>
322                     <xsl:when test="$allFailureCount &gt; 0">Failure</xsl:when>
323                 </xsl:choose>
324             </xsl:attribute>
325             <td align="center">
326                 <xsl:value-of select="$allCount" />
327             </td>
328             <xsl:if test="$allFailureCount > 0">
329                 <td align="center" style="color:red">
330                     <xsl:value-of select="$allFailureCount" />
331                 </td>
332             </xsl:if>
333             <xsl:if test="0 >= $allFailureCount">
334                 <td align="center">
335                 <xsl:value-of select="$allFailureCount" />
336                 </td>
337             </xsl:if>
338             <td align="center">
339                 <xsl:call-template name="display-percent">
340                     <xsl:with-param name="value" select="$allSuccessPercent" />
341                 </xsl:call-template>
342             </td>
343             <td align="center">
344                 <xsl:call-template name="display-time">
345                     <xsl:with-param name="value" select="$allAverageTime" />
346                 </xsl:call-template>
347             </td>
348             <td align="center">
349                 <xsl:call-template name="display-time">
350                     <xsl:with-param name="value" select="$allMinTime" />
351                 </xsl:call-template>
352             </td>
353             <td align="center">
354                 <xsl:call-template name="display-time">
355                     <xsl:with-param name="value" select="$allMaxTime" />
356                 </xsl:call-template>
357             </td>
358         </tr>
359     </table>
360 </xsl:template>
361 
362     <xsl:template name="pagelist">
363         <div class="group">Pages</div>
364          <table align="center" class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
365             <tr valign="top">
366                 <th width="50%" >请求内容</th>
367                 <th>请求数</th>
368                 <th>异常数</th>
369                 <th>成功率</th>
370                 <th>平均消耗时间</th>
371                 <th>最小消耗时间</th>
372                 <th>最大消耗时间</th>
373             </tr>
374             <xsl:for-each select="/testResults/*[not(@lb = preceding::*/@lb)]">
375                 <xsl:variable name="label" select="@lb" />
376                 <xsl:variable name="count" select="count(../*[@lb = current()/@lb])" />
377                 <xsl:variable name="failureCount" select="count(../*[@lb = current()/@lb][attribute::s=\'false\'])" />
378                 <xsl:variable name="successCount" select="count(../*[@lb = current()/@lb][attribute::s=\'true\'])" />
379                 <xsl:variable name="successPercent" select="$successCount div $count" />
380                 <xsl:variable name="totalTime" select="sum(../*[@lb = current()/@lb]/@t)" />
381                 <xsl:variable name="averageTime" select="$totalTime div $count" />
382                 <xsl:variable name="minTime">
383                     <xsl:call-template name="min">
384                         <xsl:with-param name="nodes" select="../*[@lb = current()/@lb]/@t" />
385                     </xsl:call-template>
386                 </xsl:variable>
387                 <xsl:variable name="maxTime">
388                     <xsl:call-template name="max">
389                         <xsl:with-param name="nodes" select="../*[@lb = current()/@lb]/@t" />
390                     </xsl:call-template>
391                 </xsl:variable>
392                 <tr valign="top">
393                     <xsl:attribute name="class">
394                         <xsl:choose>
395                             <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
396                         </xsl:choose>
397                     </xsl:attribute>
398                     <td class="data" >
399                           <xsl:value-of select="$label" />
400                     </td>
401                     <td align="center">
402                         <xsl:value-of select="$count" />
403                     </td>
404                     <xsl:if test="$failureCount > 0">
405                         <td align="center" style="color:red">
406                             <xsl:value-of select="$failureCount" />
407                         </td>
408                     </xsl:if>
409                     <xsl:if test="0 >= $failureCount">
410                         <td align="center">
411                         <xsl:value-of select="$failureCount" />
412                         </td>
413                     </xsl:if>
414                     <td align="center">
415                         <xsl:call-template name="display-percent">
416                             <xsl:with-param name="value" select="$successPercent" />
417                         </xsl:call-template>
418                     </td>
419                     <td align="center">
420                         <xsl:call-template name="display-time">
421                             <xsl:with-param name="value" select="$averageTime" />
422                         </xsl:call-template>
423                     </td>
424                     <td align="center">
425                         <xsl:call-template name="display-time">
426                             <xsl:with-param name="value" select="$minTime" />
427                         </xsl:call-template>
428                     </td>
429                     <td align="center">
430                         <xsl:call-template name="display-time">
431                             <xsl:with-param name="value" select="$maxTime" />
432                         </xsl:call-template>
433                     </td>
434                 </tr>
435             </xsl:for-each>
436         </table>
437     </xsl:template>
438     <xsl:template name="min">
439         <xsl:param name="nodes" select="/.." />
440         <xsl:choose>
441             <xsl:when test="not($nodes)">NaN</xsl:when>
442             <xsl:otherwise>
443                 <xsl:for-each select="$nodes">
444                     <xsl:sort data-type="number" />
445                     <xsl:if test="position() = 1">
446                         <xsl:value-of select="number(.)" />
447                     </xsl:if>
448                 </xsl:for-each>
449             </xsl:otherwise>
450         </xsl:choose>
451     </xsl:template>
452 
453     <xsl:template name="max">
454         <xsl:param name="nodes" select="/.." />
455         <xsl:choose>
456             <xsl:when test="not($nodes)">NaN</xsl:when>
457             <xsl:otherwise>
458                 <xsl:for-each select="$nodes">
459                     <xsl:sort data-type="number" order="descending" />
460                     <xsl:if test="position() = 1">
461                         <xsl:value-of select="number(.)" />
462                     </xsl:if>
463                 </xsl:for-each>
464             </xsl:otherwise>
465         </xsl:choose>
466     </xsl:template>
467 
468     <xsl:template name="display-percent">
469         <xsl:param name="value" />
470         <xsl:value-of select="format-number($value,\'0.00%\')" />
471     </xsl:template>
472 
473     <xsl:template name="display-time">
474         <xsl:param name="value" />
475         <xsl:value-of select="format-number($value,\'0 ms\')" />
476     </xsl:template>
477 
478 </xsl:stylesheet>
jmeter-result_report-new.xsl

 

 

再次按上述方法执行ant命令,出来的报告就清晰明了啦,见下图: