zoukankan      html  css  js  c++  java
  • Python组装jmx并调用JMeter执行压测

    JMeter可以通过os命令调用Python脚本,Python同样可以通过系统命令调用JMeter执行压测

    Python调用JMeter

    1. 首先要安装JMeter,官方下载地址
      解压并配置配置环境路径或建立软连,使得在命令输入jmeter便可以执行,如
    unzip apache-jmeter-5.3.zip
    mv apache-jmeter-5.3 /usr/loca/jmeter
    ln -s /usr/local/jmeter/bin/jmeter /usr/bin/jmeter
    ln -s /usr/local/jmeter/bin/jmeter-server /usr/bin/jmeter-server
    
    1. 打开JMeter并设计一个测试计划保存为testplan.jmx

    2. 使用Python调用JMeter压测并生成报告
      Python中可以使用os.system()或supprocess.Popen()调用系统命令,前者实时显示在屏幕上,后者可以获取到屏幕输出信息。
      使用Python调用JMeter运行及生成报告的命令如下。

    import subprocess
    
    jmx_file = 'testplan.jmx'  # jmx文件路径
    result_file = 'result.jtl'  # 
    log_file = 'run.log'
    report_dir = 'report'
    
    run_cmd = f'jmeter -n -t {jmx_file} -l {result_file} -j {log_file}'  # 无界面运行JMeter压测命令
    report_cmd = f'jmeter -g {result_file} -o {report_dir}'  # 生成HTML报告命令
    
    # 不需要获取屏幕输出是,可以使用os.system()
    # os.system(run_cmd)
    # os.system(report_cmd)
    
    # 需要获取屏幕输出是,可以使用subprocess.Popen()
    p1 = subprocess.Popen(run_cmd, shell=True, stdout=subprocess.PIPE)
    print(p1.stdout.read().decode('utf-8'))
    p2 = subprocess.Popen(report_cmd, shell=True, stdout=subprocess.PIPE)
    print(p2.stdout.read().decode('utf-8'))
    

    组装jmx

    每一测试计划为一个jmx文件,jmx实际上是xml格式的,包含一些JMeter自定义的格式规范。
    常用的组件有:

    • : 测试计划
    • : 线程组
    • : CSV数据文件
    • : HTTP请求
    • : HTTP请求头管理器
    • : Cookies管理器
    • : DNS缓存管理器
    • : 监听器(包括查看结果树、聚合报告等)
    • : 响应断言
    • <io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample></io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample>: 三方Dubbo请求插件

    Dubbo插件jmeter-plugins-dubbo下载链接

    jmx中,如果一个组件有子组件,格式为

    <ThreadGroup 组件基本属性>
          ...线程组配置
    </ThreadGroup>
    <hashTree>
         ...内部子组件
    </hashTree>
    ···
    如果不包含子组件,则后面接一个<hashTree/>  单标签直接结束,例如:
    ```xml
    <CSVDataSet>
        ... CSV数据组件配置
    </CSVDataSet>
    <hashTree/>
    

    详细的格式可以自己使用JMeter创建一个测试计划,使用文本文件打开jmx文件查看。

    使用Python组装jmx文件的方式有两种,一种是固定模板的数据渲染,一种类似JMeter的逐个组件添加,第一种比较简单。
    通过分析jmx文件中的变量,我们使用jinja2模板语法,将其中的变量进行参数化,对需要判断和循环的变量设置if和for循环。

    Jinja2中文文档

    假设我们的测试计划结构为:

    测试计划
        DNS缓存管理器
        Cookies管理器
        CSV文件(多个)
        ...
        聚合报告
        线程组(多个)
            CSV文件(多个)
            HTTP请求(或Dubbo请求)
                HTTP请求头管理器
                CSV文件(多个)
                响应断言
                察看结果树
    

    将jmx中的关键数据抽取并组合,我使用的完整数据格式如下:
    data.yaml

    test_plan_name: 测试计划
    comments: 测试计划描述
    hosts:
      - name: las.secoo.com
        address: 112.126.120.128
    cookies:
      clear_each_iteration: 'true'
    csv_files:
      - {'name': '数据文件1', 'path': 'data.csv', 'varnames': 'a,b', 'delimiter': ','}
      - {'name': '数据文件2', 'path': 'data.csv', 'varnames': 'c,d', 'delimiter': ','}
    thread_groups:
      - thread_group_name: 线程组1
        comments: 线程组1描述
        enabled: 'true'
        num_threads: 50
        loops: -1
        ramp_time: 0
        scheduler: 'true'
        duration: 30
        delay: ''
        http_samples:
          - request_name: HTTP-GET
            enabled: 'true'
            csv_files:
              - {'name': '数据文件4', 'path': 'data.csv', 'varnames': 'a,b', 'delimiter': ','}
            request:
              protocol: https
              domain: httpbin.org
              port: ''
              encoding: ''
              path: /get
              method: GET
              connect_timeout: ''
              response_timeout: ''
              params: {'a': 1, 'b': 2}
              headers: {'token': 'aaaaaa', 'x-text': 'bbbbb'}
              follow_redirects: 'false'
              auto_redirects: 'false'
              use_keepalive: 'false'
            validate:
              - test_field: response_data  # response_data响应文本 response_code响应代码response_message响应信息response_headers
                # 请求头request_headers  sample_label URL样本 response_data_as_document文档(文本) 请求数据request_data
                test_type: 2  # 2 包括 1匹配 8 相等  16字符串  否+4 或者+32
                strings: ['a', 'b']
          - request_name: HTTP-POST
            enabled: 'true'
            request:
              protocol: https
              domain: httpbin.org
              port: ''
              encoding: ''
              path: /post
              method: POST
              data: {'c': 3, 'd': 4}
              follow_redirects: 'false'
              auto_redirects: 'false'
              use_keepalive: 'false'
              connect_timeout: ''
              response_timeout: ''
          - request_name: HTTP-JSON
            enabled: 'true'
            request:
              protocol: https
              domain: httpbin.org
              port: ''
              encoding: ''
              path: /post
              method: POST
              connect_timeout: ''
              response_timeout: ''
              raw_data: '{"e": 5, "f": 6}'
              follow_redirects: 'false'
              auto_redirects: 'false'
              use_keepalive: 'false'
      - thread_group_name: 线程组2
        comments: 线程组2描述
        enabled: 'false'
        num_threads: 50
        loops: -1
        ramp_time: 0
        scheduler: 'true'
        duration: 30
        delay: ''
        csv_files:
          - {'name': '数据文件3', 'path': 'data.csv', 'varnames': 'a,b','delimiter': '	'}
        dubbo_samples:
          - request_name: 查询运费接口-dubbo
            enabled: 'true'
            registry:
              type: zookeeper
              group: ''
              address: 'zk-mall1.secoolocal.com:5181?backup=zk-mall2.secoolocal.com:5181,zk-mall3.secoolocal.com:5181'
            dubbo:
              timeout: 100
              retires: 0
              group: ''
              connections: 100
              load_balance: random
              cluster: failfast
              service: 'com.secoo.business.config.rpc.service.BusinessConfigStoreService'
              method: queryFreight
              headers:
                Content-Type: 'application/json'
              params:
                - type: java.util.List
                  value: ${freight_wareHouseId_sendAreaId}
                - type: java.lang.String
                  value: 110100
                - type: java.util.List
                  value: ${freight_wareHouseId_sendAreaId}
            validate:
              - test_field: response_data  # response_data响应文本 response_code响应代码response_message响应信息response_headers
                test_type: 16  # 2 包括 1匹配 8 相等  16字符串  否+4 或者+32
                strings: ['"code": 0']
    

    对应的模板文件tpl.xml代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.3">
      <hashTree>
        <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="{{test_plan_name}}" enabled="true">
          <stringProp name="TestPlan.comments">{{comments}}</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"></stringProp>
        </TestPlan>
        <hashTree>{% if hosts %}
          <DNSCacheManager guiclass="DNSCachePanel" testclass="DNSCacheManager" testname="DNS缓存管理器" enabled="true">
            <collectionProp name="DNSCacheManager.servers"/>
            <collectionProp name="DNSCacheManager.hosts">{% for host in hosts %}
              <elementProp name="las.secoo.com" elementType="StaticHost">
                <stringProp name="StaticHost.Name">{{host.name}}</stringProp>
                <stringProp name="StaticHost.Address">{{host.address}}</stringProp>
              </elementProp>{% endfor %}
            </collectionProp>
            <boolProp name="DNSCacheManager.clearEachIteration">false</boolProp>
            <boolProp name="DNSCacheManager.isCustomResolver">true</boolProp>
          </DNSCacheManager>
          <hashTree/>{% endif %} {% if cookies %}
          <CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie管理器" enabled="true">
            <collectionProp name="CookieManager.cookies"/>
            <boolProp name="CookieManager.clearEachIteration">{{cookies.clear_each_iteration}}</boolProp>
          </CookieManager>
          <hashTree/>{% endif %} {% if csv_files %}{% for csv_file in csv_files %}
          <CSVDataSet guiclass="TestBeanGUI" testclass="CSVDataSet" testname="{{csv_file.name}}" enabled="true">
            <stringProp name="filename">dat/{{csv_file.path}}</stringProp>
            <stringProp name="fileEncoding">UTF-8</stringProp>
            <stringProp name="variableNames">{{csv_file.varnames}}</stringProp>
            <boolProp name="ignoreFirstLine">true</boolProp>
            <stringProp name="delimiter">{{csv_file.delimiter}}</stringProp>
            <boolProp name="quotedData">false</boolProp>
            <boolProp name="recycle">true</boolProp>
            <boolProp name="stopThread">false</boolProp>
            <stringProp name="shareMode">shareMode.group</stringProp>
          </CSVDataSet>
          <hashTree/>{% endfor %}{% endif %}
          <ResultCollector guiclass="StatVisualizer" 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>true</responseDataOnError>
                <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
                <assertionsResultsToSave>0</assertionsResultsToSave>
                <bytes>true</bytes>
                <sentBytes>true</sentBytes>
                <threadCounts>true</threadCounts>
                <idleTime>true</idleTime>
              </value>
            </objProp>
            <stringProp name="filename"></stringProp>
          </ResultCollector>
          <hashTree/>{% for thread_group in thread_groups %}
          <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="{{thread_group.thread_group_name}}" enabled="{{thread_group.enabled}}">
            <stringProp name="TestPlan.comments">{{thread_group.comments}}</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>
              <intProp name="LoopController.loops">{{thread_group.loops}}</intProp>
            </elementProp>
            <stringProp name="ThreadGroup.num_threads">{{thread_group.num_threads}}</stringProp>
            <stringProp name="ThreadGroup.ramp_time">{{thread_group.ramp_time}}</stringProp>
            <boolProp name="ThreadGroup.scheduler">{{thread_group.scheduler}}</boolProp>
            <stringProp name="ThreadGroup.duration">{{thread_group.duration}}</stringProp>
            <stringProp name="ThreadGroup.delay">{{thread_group.delay}}</stringProp>
            <boolProp name="ThreadGroup.same_user_on_next_iteration">false</boolProp>
          </ThreadGroup>
          <hashTree>{% if thread_group.csv_files %}{% for csv_file in thread_group.csv_files %}
            <CSVDataSet guiclass="TestBeanGUI" testclass="CSVDataSet" testname="{{csv_file.name}}" enabled="true">
            <stringProp name="filename">dat/{{csv_file.path}}</stringProp>
            <stringProp name="fileEncoding">UTF-8</stringProp>
            <stringProp name="variableNames">{{csv_file.varnames}}</stringProp>
            <boolProp name="ignoreFirstLine">true</boolProp>
            <stringProp name="delimiter">{{csv_file.delimiter}}</stringProp>
            <boolProp name="quotedData">false</boolProp>
            <boolProp name="recycle">true</boolProp>
            <boolProp name="stopThread">false</boolProp>
            <stringProp name="shareMode">shareMode.group</stringProp>
          </CSVDataSet>
            <hashTree/>{% endfor %}{% endif %} {% if thread_group.http_samples %}{% for http_sample in thread_group.http_samples %}
            <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="{{http_sample.request_name}}" enabled="{{http_sample.enabled}}">
              <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
                <collectionProp name="Arguments.arguments">{% if http_sample.request.params %}{% for name, value in http_sample.request.params.items() %}
                  <elementProp name="{{name}}" elementType="HTTPArgument">
                    <boolProp name="HTTPArgument.always_encode">false</boolProp>
                    <stringProp name="Argument.value">{{value}}</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                    <boolProp name="HTTPArgument.use_equals">true</boolProp>
                    <stringProp name="Argument.name">{{name}}</stringProp>
                  </elementProp>{% endfor %}{% endif %} {% if http_sample.request.data %}{% for name, value in http_sample.request.data.items() %}
                  <elementProp name="{{name}}" elementType="HTTPArgument">
                    <boolProp name="HTTPArgument.always_encode">false</boolProp>
                    <stringProp name="Argument.value">{{value}}</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                    <boolProp name="HTTPArgument.use_equals">true</boolProp>
                    <stringProp name="Argument.name">{{name}}</stringProp>
                  </elementProp>{% endfor %}{% endif %} {% if http_sample.request.raw_data %}
                  <elementProp name="" elementType="HTTPArgument">
                    <boolProp name="HTTPArgument.always_encode">false</boolProp>
                    <stringProp name="Argument.value">{{http_sample.request.raw_data}}</stringProp>
                    <stringProp name="Argument.metadata">=</stringProp>
                  </elementProp>{% endif %}
                </collectionProp>
              </elementProp>
              <stringProp name="HTTPSampler.domain">{{http_sample.request.domain}}</stringProp>
              <stringProp name="HTTPSampler.port">{{http_sample.request.port}}</stringProp>
              <stringProp name="HTTPSampler.protocol">{{http_sample.request.protocol}}</stringProp>
              <stringProp name="HTTPSampler.contentEncoding">{{http_sample.request.encoding}}</stringProp>
              <stringProp name="HTTPSampler.path">{{http_sample.request.path}}</stringProp>
              <stringProp name="HTTPSampler.method">{{http_sample.request.method}}</stringProp>
              <boolProp name="HTTPSampler.follow_redirects">{{http_sample.request.follow_redirects}}</boolProp>
              <boolProp name="HTTPSampler.auto_redirects">{{http_sample.request.auto_redirects}}</boolProp>
              <boolProp name="HTTPSampler.use_keepalive">{{http_sample.request.use_keepalive}}</boolProp>
              <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
              <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
              <stringProp name="HTTPSampler.connect_timeout">{{http_sample.request.connect_timeout}}</stringProp>
              <stringProp name="HTTPSampler.response_timeout">{{http_sample.request.response_timeout}}</stringProp>
            </HTTPSamplerProxy>
            <hashTree>{% if http_sample.request.headers %}
              <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP信息头管理器" enabled="true">
                <collectionProp name="HeaderManager.headers">{% for name, value in http_sample.request.headers.items() %}
                  <elementProp name="" elementType="Header">
                    <stringProp name="Header.name">{{name}}</stringProp>
                    <stringProp name="Header.value">{{value}}</stringProp>
                  </elementProp>{% endfor %}
                </collectionProp>
              </HeaderManager>
              <hashTree/>{% endif %} {% if http_sample.csv_files %}{% for csv_file in http_sample.csv_files %}
              <CSVDataSet guiclass="TestBeanGUI" testclass="CSVDataSet" testname="CSV 数据文件设置" enabled="true">
                <stringProp name="delimiter">{{csv_file.delimiter}}</stringProp>
                <stringProp name="fileEncoding">UTF_8</stringProp>
                <stringProp name="filename">dat/{{csv_file.path}}</stringProp>
                <boolProp name="ignoreFirstLine">true</boolProp>
                <boolProp name="quotedData">false</boolProp>
                <boolProp name="recycle">true</boolProp>
                <stringProp name="shareMode">shareMode.group</stringProp>
                <boolProp name="stopThread">false</boolProp>
                <stringProp name="variableNames">{{csv_file.varnames}}</stringProp>
              </CSVDataSet>
              <hashTree/>{% endfor %}{% endif %} {% if http_sample.validate %}{% for assertion in http_sample.validate %}
              <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="响应断言" enabled="true">
                <collectionProp name="Asserion.test_strings">{% if assertion.strings %}{% for string in assertion.strings %}
                  <stringProp name="97">{{string}}</stringProp>{% endfor %}{% endif %}
                </collectionProp>
                <stringProp name="Assertion.custom_message"></stringProp>
                <stringProp name="Assertion.test_field">Assertion.{{assertion.test_field}}</stringProp>
                <boolProp name="Assertion.assume_success">false</boolProp>
                <intProp name="Assertion.test_type">{{assertion.test_type}}</intProp>
              </ResponseAssertion>
              <hashTree/>{% endfor %}{% endif %}
              <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>{% endfor %}{% endif %} {% if thread_group.dubbo_samples %} {% for dubbo_sample in thread_group.dubbo_samples %}
            <io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample guiclass="io.github.ningyu.jmeter.plugin.dubbo.gui.DubboSampleGui" testclass="io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample" testname="{{dubbo_sample.request_name}}" enabled="{{dubbo_sample.enabled}}">
              <stringProp name="FIELD_DUBBO_REGISTRY_PROTOCOL">{{dubbo_sample.registry.type}}</stringProp>
              <stringProp name="FIELD_DUBBO_REGISTRY_GROUP">{{dubbo_sample.registry.group}}</stringProp>
              <stringProp name="FIELD_DUBBO_RPC_PROTOCOL">dubbo://</stringProp>
              <stringProp name="FIELD_DUBBO_ADDRESS">{{dubbo_sample.registry.address}}</stringProp>
              <stringProp name="FIELD_DUBBO_TIMEOUT">{{dubbo_sample.dubbo.timeout}}</stringProp>
              <stringProp name="FIELD_DUBBO_VERSION"></stringProp>
              <stringProp name="FIELD_DUBBO_RETRIES">{{dubbo_sample.dubbo.retries}}</stringProp>
              <stringProp name="FIELD_DUBBO_GROUP">{{dubbo_sample.dubbo.group}}</stringProp>
              <stringProp name="FIELD_DUBBO_CONNECTIONS">{{dubbo_sample.dubbo.connections}}</stringProp>
              <stringProp name="FIELD_DUBBO_LOADBALANCE">{{dubbo_sample.dubbo.load_balance}}</stringProp>
              <stringProp name="FIELD_DUBBO_ASYNC">sync</stringProp>
              <stringProp name="FIELD_DUBBO_CLUSTER">{{dubbo_sample.dubbo.cluster}}</stringProp>
              <stringProp name="FIELD_DUBBO_INTERFACE">{{dubbo_sample.dubbo.service}}</stringProp>
              <stringProp name="FIELD_DUBBO_METHOD">{{dubbo_sample.dubbo.method}}</stringProp>
              <intProp name="FIELD_DUBBO_METHOD_ARGS_SIZE">1</intProp>{% for param in dubbo_sample.dubbo.params %}
                <stringProp name="FIELD_DUBBO_METHOD_ARGS_PARAM_TYPE1">{{param.type}}</stringProp>
                <stringProp name="FIELD_DUBBO_METHOD_ARGS_PARAM_VALUE1">{{param.value}}</stringProp>{% endfor %}
              <intProp name="FIELD_DUBBO_ATTACHMENT_ARGS_SIZE">0</intProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_PROTOCOL"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_GROUP"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_NAMESPACE"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_USER_NAME"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_PASSWORD"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_ADDRESS"></stringProp>
              <stringProp name="FIELD_DUBBO_CONFIG_CENTER_TIMEOUT"></stringProp>
              <stringProp name="FIELD_DUBBO_REGISTRY_USER_NAME"></stringProp>
              <stringProp name="FIELD_DUBBO_REGISTRY_PASSWORD"></stringProp>
              <stringProp name="FIELD_DUBBO_REGISTRY_TIMEOUT"></stringProp>
            </io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample>
            <hashTree>{% if dubbo_sample.dubbo.headers %}
              <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP信息头管理器" enabled="true">
                <collectionProp name="HeaderManager.headers">{% for name, value in dubbo_sample.dubbo.headers.items() %}
                  <elementProp name="" elementType="Header">
                    <stringProp name="Header.name">{{name}}</stringProp>
                    <stringProp name="Header.value">{{value}}</stringProp>
                  </elementProp>{% endfor %}
                </collectionProp>
              </HeaderManager>
              <hashTree/>{% endif %} {% if dubbo_sample.validate %} {% for assertion in dubbo_sample.validate %}
              <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="响应断言" enabled="true">
                <collectionProp name="Asserion.test_strings">{% if assertion.strings %}{% for string in assertion.strings %}
                  <stringProp name="97">{{string}}</stringProp>{% endfor %}{% endif %}
                </collectionProp>
                <stringProp name="Assertion.custom_message"></stringProp>
                <stringProp name="Assertion.test_field">Assertion.{{assertion.test_field}}</stringProp>
                <boolProp name="Assertion.assume_success">false</boolProp>
                <intProp name="Assertion.test_type">{{assertion.test_type}}</intProp>
              </ResponseAssertion>{% endfor %} {% endif %}
              <hashTree/>{% endfor %}{% endif %} {% endfor %}
          </hashTree>
        </hashTree>
      </hashTree>
    </jmeterTestPlan>
    

    组装出类似data.yaml格式的数据,并使用jinja2渲染模板即可得到完整的jmx文件

    pip install pyyaml jinja2

    import yaml
    import jinja2
    
    # 组装或读取数据
    with open('data.yaml', encoding='utf-8') as f:
        data = yaml.safe_load(f)
    
     # 读取模板
    with open('tpl.xml', encoding='utf-8') as f:
        tpl = f.read()
    
    # 渲染模板生成jmx
    jmx = jinja2.Template(tpl).render(data)
    with open(jmx_file, 'w', encoding='utf-8') as f:
        f.write(jmx)
    

    后计

    在实际项目中,还涉及数据文件的拷贝,节点环境的部署,脚本的分发,报告的下载等等,可以使用paramiko或者fabric或ansible完成,压测节点数据分发的服务管理。

  • 相关阅读:
    程序员:不要自称为码农
    SpringBoot对静态资源配置
    LeetCode 572. Subtree of Another Tree(子树)
    LeetCode 437. Path Sum III(统计路径和等于sum的路径数量)
    LeetCode 112. Path Sum(判断路径和是否等于一个数)
    LeetCode 617. Merge Two Binary Trees(归并两棵二叉树)
    LeetCode 226. Invert Binary Tree(翻转二叉树)
    Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom:2.6 的解决办法
    linux-查询某软件的安装的目录
    WebService概念解释
  • 原文地址:https://www.cnblogs.com/superhin/p/13887905.html
Copyright © 2011-2022 走看看