之前的文章写了怎么用python生成JMeter脚本,生成了测试计划、线程组、Http监听器、响应断言、查看结果树,详细内容可以去主页查看之前的文章。本篇内容接着讲怎么用python生成汇总报告、聚合报告和相应时间图组件。
汇总报告的格式与查看结果树的格式类似,所以代码大体与查看结果树一样,同样使用set方法修改汇总报告组件的参数,然后用get方法生成组件。
import xml.etree.ElementTree as ET
from base import General
class JMeterSummaryReport:
def __init__(self):
self.__name = '汇总报告'
# 显示日志内容 为true时勾选仅错误日志
self.__error_logging = 'false'
# 显示日志内容 为true时勾选仅成功日志,与错误日志只能选择一个
self.__success_only_logging = ''
# 数据写入文件的文件名称
self.__filename = ''
# 示例保存配置
self.__sample_save_config = {
'time': 'true',
'latency': 'true',
'timestamp': 'true',
'success': 'true',
'label': 'true',
'code': 'true',
'message': 'true',
'threadName': 'true',
'dataType': 'true',
'encoding': 'false',
'assertions': 'true',
'subresults': 'true',
'responseData': 'false',
'samplerData': 'false',
'xml': 'false',
'fieldNames': 'true',
'responseHeaders': 'false',
'requestHeaders': 'false',
'responseDataOnError': 'false',
'saveAssertionResultsFailureMessage': 'true',
'assertionsResultsToSave': '0',
'bytes': 'true',
'sentBytes': 'true',
'url': 'true',
'threadCounts': 'true',
'idleTime': 'true',
'connectTime': 'true'
}
def get_name(self):
return self.__name
def set__name(self, name):
self.__name = name
def get_error_logging(self):
return self.__error_logging
def set_error_logging(self, error_logging):
self.__error_logging = error_logging
def get_success_only_logging(self):
return self.__success_only_logging
def set_success_only_logging(self, success_only_logging):
self.__success_only_logging = success_only_logging
def get_filename(self):
return self.__filename
def set_filename(self, filename):
self.__filename = filename
def get_sample_save_config(self):
return self.__sample_save_config
def set_sample_save_config(self, sample_save_config: dict):
self.__sample_save_config = sample_save_config
def set_config(self, config: dict):
for key, value in config.items():
self.__sample_save_config[key] = value
def items(self):
dicts = {
'error_logging': self.__error_logging,
'success_only_logging': self.__success_only_logging,
'filename': self.__filename
}
return dicts
def get(self, parent):
prop_map = {
'error_logging': General.add_bool_prop,
'success_only_logging': General.add_bool_prop,
'filename': General.add_str_prop
}
keys_map = {
'error_logging': 'ResultCollector.error_logging',
'success_only_logging': 'ResultCollector.success_only_logging',
'filename': 'filename'
}
summary_report_prop = ET.SubElement(parent, 'ResultCollector')
summary_report_prop.set('guiclass', 'SummaryReport')
summary_report_prop.set('testclass', 'ResultCollector')
summary_report_prop.set('testname', self.__name)
for key, value in self.items().items():
if key in prop_map:
prop_map[key](self, summary_report_prop, keys_map[key], str(value))
# if value == '' or value == 'false':
# pass
# else:
# prop_map[key](self, result_collector_prop, keys_map[key], str(value))
obj_prop = ET.SubElement(summary_report_prop, 'objProp')
config_name_prop = ET.SubElement(obj_prop, 'name')
config_name_prop.text = 'saveConfig'
value_prop = ET.SubElement(obj_prop, 'value')
value_prop.set('class', 'SampleSaveConfiguration')
for key, value in self.__sample_save_config.items():
props = ET.SubElement(value_prop, key)
props.text = str(value)
hashtree = ET.SubElement(parent, 'hashTree')
return summary_report_prop
聚合报告的格式与汇总报告的格式类似,所以代码大体与汇总报告一样,同样使用set方法修改汇总报告组件的参数,然后用get方法生成组件。
import xml.etree.ElementTree as ET
from base import General
class JMeterStatVisualizer:
def __init__(self):
self.__name = '聚合报告'
# 显示日志内容 为true时勾选仅错误日志
self.__error_logging = 'false'
# 显示日志内容 为true时勾选仅成功日志,与错误日志只能选择一个
self.__success_only_logging = ''
# 数据写入文件的文件名称
self.__filename = ''
# 示例保存配置
self.__sample_save_config = {
'time': 'true',
'latency': 'true',
'timestamp': 'true',
'success': 'true',
'label': 'true',
'code': 'true',
'message': 'true',
'threadName': 'true',
'dataType': 'true',
'encoding': 'false',
'assertions': 'true',
'subresults': 'true',
'responseData': 'false',
'samplerData': 'false',
'xml': 'false',
'fieldNames': 'true',
'responseHeaders': 'false',
'requestHeaders': 'false',
'responseDataOnError': 'false',
'saveAssertionResultsFailureMessage': 'true',
'assertionsResultsToSave': '0',
'bytes': 'true',
'sentBytes': 'true',
'url': 'true',
'threadCounts': 'true',
'idleTime': 'true',
'connectTime': 'true'
}
def get_name(self):
return self.__name
def set__name(self, name):
self.__name = name
def get_error_logging(self):
return self.__error_logging
def set_error_logging(self, error_logging):
self.__error_logging = error_logging
def get_success_only_logging(self):
return self.__success_only_logging
def set_success_only_logging(self, success_only_logging):
self.__success_only_logging = success_only_logging
def get_filename(self):
return self.__filename
def set_filename(self, filename):
self.__filename = filename
def get_sample_save_config(self):
return self.__sample_save_config
def set_sample_save_config(self, sample_save_config: dict):
self.__sample_save_config = sample_save_config
def set_config(self, config: dict):
for key, value in config.items():
self.__sample_save_config[key] = value
def items(self):
dicts = {
'error_logging': self.__error_logging,
'success_only_logging': self.__success_only_logging,
'filename': self.__filename
}
return dicts
def get(self, parent):
prop_map = {
'error_logging': General.add_bool_prop,
'success_only_logging': General.add_bool_prop,
'filename': General.add_str_prop
}
keys_map = {
'error_logging': 'ResultCollector.error_logging',
'success_only_logging': 'ResultCollector.success_only_logging',
'filename': 'filename'
}
stat_visualizer_prop = ET.SubElement(parent, 'ResultCollector')
stat_visualizer_prop.set('guiclass', 'StatVisualizer')
stat_visualizer_prop.set('testclass', 'ResultCollector')
stat_visualizer_prop.set('testname', self.__name)
for key, value in self.items().items():
if key in prop_map:
prop_map[key](self, stat_visualizer_prop, keys_map[key], str(value))
# if value == '' or value == 'false':
# pass
# else:
# prop_map[key](self, result_collector_prop, keys_map[key], str(value))
obj_prop = ET.SubElement(stat_visualizer_prop, 'objProp')
config_name_prop = ET.SubElement(obj_prop, 'name')
config_name_prop.text = 'saveConfig'
value_prop = ET.SubElement(obj_prop, 'value')
value_prop.set('class', 'SampleSaveConfiguration')
for key, value in self.__sample_save_config.items():
props = ET.SubElement(value_prop, key)
props.text = str(value)
hashtree = ET.SubElement(parent, 'hashTree')
return stat_visualizer_prop
响应时间图的大体格式与前两者的格式也类似,不过响应时间图多了许多配置参数,通过这些参数可以修改响应时间图展示的样式等信息。具体的参数说明,已经在代码中做了注释。在使用的时候可以根据参数的注释来设置参数。
import xml.etree.ElementTree as ET
from base import General
class JMeterRespTimeGraphVisualizer:
def __init__(self):
self.__name = '响应时间图'
# 显示日志内容 为true时勾选仅错误日志
self.__error_logging = 'false'
# 显示日志内容 为true时勾选仅成功日志,与错误日志只能选择一个
self.__success_only_logging = ''
# 数据写入文件的文件名称
self.__filename = ''
# 时间间隔,为空时默认10秒/10000ms
self.__interval = ''
# 取样器标签选择,默认为空,不勾选,勾选为true
self.__seriesselection = ''
# 取样器标签选择输入
self.__seriesselection_match_label = ''
# 取样器标签区分大小写, 默认为空,不勾选,勾选为true
self.__seriesselectioncasesensitive = ''
# 取样器正则表达式, 默认为空,勾选,不勾选为false
self.__seriesselectionregexp = ''
# 图标题
self.__graphtitle = ''
# 描边宽度, 默认为3.0f 0 1.0f 1 1.5f 2 2.0f 3 2.5f 5 3.5f 以此类推最终到6.5f对应的值为11
self.__linestrockwidth = ''
# 形状 默认空为原型 1 菱形 2 正方形 3 三角形 4 空
self.__lineshapepoint = ''
# 动态图形大小,默认为空,勾选状态
self.__graphsizedynamic = ''
# 非动态图标的宽和高,配合动态图形大小为false时使用
self.__graphsizewidth = ''
self.__graphsizeheight = ''
# 时间格式 默认为空的时候是 HH:mm:ss
self.__xaxistimeformat = ''
# Y轴最大值
self.__yaxisscalemaxvalue = ''
# Y轴增量比例
self.__yaxisscaleincrement = ''
# Y轴显示号码分组,默认勾选为空,取消勾选为false
self.__yaxisnumbergrouping = ''
# 图例位置 默认为空,对应底部位置 1 右 2 左 3 顶部
self.__legendplacement = ''
# 图例字体 默认为空,对应无衬线体 1 衬线体
self.__legendfont = ''
# 图例字体尺寸 默认为空,对应尺寸为10 下标【0,1,2,3,4,5,6,7,8,9,10.11】对应尺寸为【8,9,10,11,12,14,16,18,20,24,28,32】
self.__legendsize = ''
# 图例字体样式 默认为空,对应样式普通, 1 粗体 2 斜体
self.__legendstyle = ''
# 示例保存配置
self.__sample_save_config = {
'time': 'true',
'latency': 'true',
'timestamp': 'true',
'success': 'true',
'label': 'true',
'code': 'true',
'message': 'true',
'threadName': 'true',
'dataType': 'true',
'encoding': 'false',
'assertions': 'true',
'subresults': 'true',
'responseData': 'false',
'samplerData': 'false',
'xml': 'false',
'fieldNames': 'true',
'responseHeaders': 'false',
'requestHeaders': 'false',
'responseDataOnError': 'false',
'saveAssertionResultsFailureMessage': 'true',
'assertionsResultsToSave': '0',
'bytes': 'true',
'sentBytes': 'true',
'url': 'true',
'threadCounts': 'true',
'idleTime': 'true',
'connectTime': 'true'
}
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
def get_error_logging(self):
return self.__error_logging
def set_error_logging(self, error_logging):
self.__error_logging = error_logging
def get_success_only_logging(self):
return self.__success_only_logging
def set_success_only_logging(self, success_only_logging):
self.__success_only_logging = success_only_logging
def get_filename(self):
return self.__filename
def set_filename(self, filename):
self.__filename = filename
def get_sample_save_config(self):
return self.__sample_save_config
def set_sample_save_config(self, sample_save_config: dict):
self.__sample_save_config = sample_save_config
def set_config(self, config: dict):
for key, value in config.items():
self.__sample_save_config[key] = value
def get_interval(self):
return self.__interval
def set_interval(self, interval):
self.__interval = interval
def get_seriesselection(self):
return self.__seriesselection
def set_seriesselection(self, seriesselection):
self.__seriesselection = seriesselection
def get_seriesselection_match_label(self):
return self.seriesselection_match_label
def set_seriesselection_match_label(self, seriesselection_match_label):
self.__seriesselection_match_label = seriesselection_match_label
def get_seriesselectioncasesensitive(self):
return self.__seriesselectioncasesensitive
def set_seriesselectioncasesensitive(self, seriesselectioncasesensitive):
self.__seriesselectioncasesensitive = seriesselectioncasesensitive
def get_seriesselectionregexp(self):
return self.__seriesselectionregexp
def set_seriesselectionregexp(self, seriesselectionregexp):
self.__seriesselectionregexp = seriesselectionregexp
def get_graphtitle(self):
return self.__graphtitle
def set_graphtitle(self, graphtitle):
self.__graphtitle = graphtitle
def get_linestrockwidth(self):
return self.__linestrockwidth
def set_linestrockwidth(self, linestrockwidth):
self.linestrockwidth = linestrockwidth
def get_lineshapepoint(self):
return self.__lineshapepoint
def set_lineshapepoint(self, lineshapepoint):
self.__lineshapepoint = lineshapepoint
def get_graphsizedynamic(self):
return self.__graphsizedynamic
def set_graphsizedynamic(self, graphsizedynamic):
self.__graphsizedynamic = graphsizedynamic
def get_graphsizewidth(self):
return self.__graphsizewidth
def set_graphsizewidth(self, graphsizewidth):
self.__graphsizewidth = graphsizewidth
def get_graphsizeheight(self):
return self.__graphsizeheight
def set_graphsizeheight(self, graphsizeheight):
self.graphsizeheight = graphsizeheight
def get_xaxistimeformat(self):
return self.__xaxistimeformat
def set_xaxistimeformat(self, xaxistimeformat):
self.__xaxistimeformat = xaxistimeformat
def get_yaxisscalemaxvalue(self):
return self.__yaxisscalemaxvalue
def set_yaxisscalemaxvalue(self, yaxisscalemaxvalue):
self.__yaxisscalemaxvalue = yaxisscalemaxvalue
def get_yaxisnumbergrouping(self):
return self.__yaxisnumbergrouping
def set_yaxisnumbergrouping(self, yaxisnumbergrouping):
self.__yaxisnumbergrouping = yaxisnumbergrouping
def get_legendplacement(self):
return self.__legendplacement
def set_legendplacement(self, legendplacement):
self.__legendplacement = legendplacement
def get_legendfont(self):
return self.__legendfont
def set_legendfont(self, legendfont):
self.__legendfont = legendfont
def get_legendsize(self):
return self.__legendsize
def set_legendsize(self, legendsize):
self.__legendsize = legendsize
def get_legendstyle(self):
return self.__legendstyle
def set_legendstyle(self, legendstyle):
self.__legendstyle = legendstyle
def items(self):
dicts = {
'error_logging': self.__error_logging,
'success_only_logging': self.__success_only_logging,
'filename': self.__filename,
'interval': self.__interval,
'seriesselection': self.__seriesselection,
'seriesselection_match_label': self.__seriesselection_match_label,
'seriesselectioncasesensitive': self.__seriesselectioncasesensitive,
'seriesselectionregexp': self.__seriesselectionregexp,
'graphtitle': self.__graphtitle,
'linestrockwidth': self.__linestrockwidth,
'lineshapepoint': self.__lineshapepoint,
'graphsizedynamic': self.__graphsizedynamic,
'graphsizewidth': self.__graphsizewidth,
'graphsizeheight': self.__graphsizeheight,
'xaxistimeformat': self.__xaxistimeformat,
'yaxisscalemaxvalue': self.__yaxisscalemaxvalue,
'yaxisnumbergrouping': self.__yaxisnumbergrouping,
'yaxisscaleincrement': self.__yaxisscaleincrement,
'legendplacement': self.__legendplacement,
'legendfont': self.__legendfont,
'legendsize': self.__legendsize,
'legendstyle': self.__legendstyle
}
return dicts
def get(self, parent):
prop_map = {
'error_logging': General.add_bool_prop,
'success_only_logging': General.add_bool_prop,
'filename': General.add_str_prop,
'interval': General.add_str_prop,
'seriesselection': General.add_bool_prop,
'seriesselection_match_label': General.add_str_prop,
'seriesselectioncasesensitive': General.add_bool_prop,
'seriesselectionregexp': General.add_bool_prop,
'graphtitle': General.add_str_prop,
'linestrockwidth': General.add_int_prop,
'lineshapepoint': General.add_int_prop,
'graphsizedynamic': General.add_bool_prop,
'graphsizewidth': General.add_str_prop,
'graphsizeheight': General.add_str_prop,
'xaxistimeformat': General.add_str_prop,
'yaxisscalemaxvalue': General.add_str_prop,
'yaxisnumbergrouping': General.add_bool_prop,
'yaxisscaleincrement': General.add_str_prop,
'legendplacement': General.add_int_prop,
'legendfont': General.add_int_prop,
'legendsize': General.add_int_prop,
'legendstyle': General.add_int_prop
}
keys_map = {
'error_logging': 'ResultCollector.error_logging',
'success_only_logging': 'ResultCollector.success_only_logging',
'filename': 'filename',
'interval': 'RespTimeGraph.interval',
'seriesselection': 'RespTimeGraph.seriesselection',
'seriesselection_match_label': 'RespTimeGraph.seriesselectionmatchlabel',
'seriesselectioncasesensitive': 'RespTimeGraph.seriesselectioncasesensitive',
'seriesselectionregexp': 'RespTimeGraph.seriesselectionregexp',
'graphtitle': 'RespTimeGraph.graphtitle',
'linestrockwidth': 'RespTimeGraph.linestrockwidth',
'lineshapepoint': 'RespTimeGraph.lineshapepoint',
'graphsizedynamic': 'RespTimeGraph.graphsizedynamic',
'graphsizewidth': 'RespTimeGraph.graphsizewidth',
'graphsizeheight': 'RespTimeGraph.graphsizeheight',
'xaxistimeformat': 'RespTimeGraph.xaxistimeformat',
'yaxisscalemaxvalue': 'RespTimeGraph.yaxisscalemaxvalue',
'yaxisnumbergrouping': 'RespTimeGraph.yaxisnumbergrouping',
'yaxisscaleincrement': 'RespTimeGraph.yaxisscaleincrement',
'legendplacement': 'RespTimeGraph.legendplacement',
'legendfont': 'RespTimeGraph.legendfont',
'legendsize': 'RespTimeGraph.legendsize',
'legendstyle': 'RespTimeGraph.legendstyle'
}
resp_time_graph_visualizer_prop = ET.SubElement(parent, 'ResultCollector')
resp_time_graph_visualizer_prop.set('guiclass', 'RespTimeGraphVisualizer')
resp_time_graph_visualizer_prop.set('testclass', 'ResultCollector')
resp_time_graph_visualizer_prop.set('testname', self.__name)
for key, value in self.items().items():
if key in prop_map:
# prop_map[key](self, resp_time_graph_visualizer_prop, keys_map[key], str(value))
if value == '' or value == 'false':
pass
else:
prop_map[key](self, resp_time_graph_visualizer_prop, keys_map[key], str(value))
obj_prop = ET.SubElement(resp_time_graph_visualizer_prop, 'objProp')
config_name_prop = ET.SubElement(obj_prop, 'name')
config_name_prop.text = 'saveConfig'
value_prop = ET.SubElement(obj_prop, 'value')
value_prop.set('class', 'SampleSaveConfiguration')
for key, value in self.__sample_save_config.items():
props = ET.SubElement(value_prop, key)
props.text = str(value)
hashtree = ET.SubElement(parent, 'hashTree')
return resp_time_graph_visualizer_prop
#生成JMeter脚本demo
在生产jmeter脚本时,要注意每个组件之间的树形关系,需要传入正确的parent,防止生产脚本报错。
import xml.etree.ElementTree as ET
import JMeter
from JMeterThreadGroup import JMeterThreadGroup
from JMeterTestPlan import JMeterTestPlan
from JMeterHttpSampler import JMeterHttpSampler
from JMeterResponseAssert import JMeterResponseAssert
from JMeterViewResultsFullVisualizer import JMeterViewResultsFullVisualizer
from JMeterSummaryReport import JMeterSummaryReport
from JMeterStatVisualizer import JMeterStatVisualizer
from JMeterRespTimeGraphVisualizer import JMeterRespTimeGraphVisualizer
import base
class GenJMeter:
jmeter_script = JMeter.get()
hash_tree = ET.SubElement(jmeter_script, 'hashTree')
test_plan = JMeterTestPlan()
test_plan = test_plan.get(hash_tree)
thread_group_tree = ET.SubElement(hash_tree, 'hashTree')
thread_group = JMeterThreadGroup().get(thread_group_tree)
test_hashtree = ET.SubElement(thread_group_tree, 'hashTree')
http_sampler = JMeterHttpSampler()
http_sampler.set_params({'test': 123})
http_sampler.set_files({'file': 'test.txt'})
http_sampler.get(test_hashtree)
response_assert = JMeterResponseAssert()
response_assert.set_assert_name('断言')
response_assert.set_assert_text(['test', '123'])
response_assert.set_test_type('2')
response_assert.get(test_hashtree)
result_collector_prop = JMeterViewResultsFullVisualizer()
result_collector_prop.get(test_hashtree)
summary_report = JMeterSummaryReport()
summary_report.get(test_hashtree)
stat_visualizer = JMeterStatVisualizer()
stat_visualizer.get(test_hashtree)
resp_time_graph = JMeterRespTimeGraphVisualizer()
resp_time_graph.get(test_hashtree)
bases = base.General()
tree = ET.ElementTree(jmeter_script)
bases.indent(jmeter_script)
with open('text.jmx', "wb") as f:
tree.write(f, encoding="utf-8", xml_declaration=True, method="xml")
其他组件实现方式待续