前面实现了第一种方法,就是通过写文件,然后参数化读取。 现在来讲第二种实现,直接改脚本里面数据。 首先jmeter文件存储为xml类型的。我们得熟悉python处理xml. python有几种处理xml的库,这里讲ElementTree 类似一个轻量级的DOM。 python3.3之后ElementTree模块会自动寻找可用的C库来加快速度
代码语言:javascript复制try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
tree = ET.parse("country.xml") # <class 'xml.etree.ElementTree.ElementTree'>
root = tree.getroot() # 获取根节点 <Element 'data' at 0x02BF6A80>
XML文件格式介绍:
代码语言:javascript复制<tag attrib = > text </tag> tail
例:<APP_KEY channel = 'CSDN'> hello123456789 </APP_KEY>
tag,即标签,用于标识该元素表示哪种数据,即APP_KEY
attrib,即属性,用Dictionary形式保存,即{'channel' = 'CSDN'}
text,文本字符串,可以用来存储一些数据,即hello123456789
tail,尾字符串,并不是必须的,例子中没有包含。
ElementTree解析XML文件的过程: 导入ElementTree,
代码语言:javascript复制import xml.etree.ElementTree as ET
解析Xml文件找到根节点: 直接解析XML文件并获得根节点,
代码语言:javascript复制tree = ET.parse('country_data.xml') root = tree.getroot()
解析字符串,
代码语言:javascript复制root = ET.fromstring(country_data_as_string)
遍历根节点可以获得子节点,然后就可以根据需求拿到需要的字段了。
查找指定的子节点: 当XML文件较大或者其中的子节点tag非常多的时候,一个一个获取是比较麻烦的而且有很多不是我们需要的,这样我们可以通过find('nodeName')或者findall('nodeName')方法来查找指定tag的节点。
代码语言:javascript复制find('nodeName'):表示在该节点下,查找其中第一个tag为nodeName的节点。
findall('nodeName'):表示在该节点下,查找其中所有tag为nodeName的节点。
2.遍历
1)简单遍历
代码语言:javascript复制import xml.etree.ElementTree as ET
tree = ET.parse("country.xml")
root = tree.getroot() print(root.tag, ":", root.attrib) # 打印根元素的tag和属性
# 遍历xml文档的第二层
for child in root: # 第二层节点的标签名称和属性
print(child.tag,":", child.attrib) # 遍历xml文档的第三层
for children in child: # 第三层节点的标签名称和属性
print(children.tag, ":", children.attrib)
可以通过下标的方式直接访问节点
代码语言:javascript复制# 访问根节点下第一个country的第二个节点year,获取对应的文本
year = root[0][1].text # 2008
2)ElementTree提供的方法
find
(match) # 查找第一个匹配的子元素, match可以时tag或是xpaht路径findall
(match) # 返回所有匹配的子元素列表findtext
(match, default=None) #iter
(tag=None) # 以当前元素为根节点 创建树迭代器,如果tag不为None,则以tag进行过滤iterfind
(match*) # *
例子:
代码语言:javascript复制# 遍历所有的counry标签
for country in root.findall("country"): # 查找country标签下的第一个rank标签
rank = country.find("rank").text # 获取country标签的name属性
name = country.get("name") print(name, rank)
3.修改xml结构
- 属性相关
# 将所有的rank值加1,并添加属性updated为yes
for rank in root.iter("rank"):
new_rank = int(rank.text) 1
rank.text = str(new_rank) # 必须将int转为str
rank.set("updated", "yes") # 添加属性
# 再终端显示整个xml
ET.dump(root) # 注意 修改的内容存在内存中 尚未保存到文件中 # 保存修改后的内容
tree.write("output.xml")
import xml.etree.ElementTree as ET
tree = ET.parse("output.xml")
root = tree.getroot() for rank in root.iter("rank"): # attrib为属性字典
# 删除对应的属性updated
del rank.attrib['updated']
ET.dump(root)
小结: 关于*class *xml.etree.ElementTree.``Element 属性相关
- attrib 为包含元素属性的字典
keys() 返回元素属性名称列表
- items() 返回(name,value)列表
get
(key, default=None) 获取属性set
(key, value) # 更新/添加 属性- del xxx.attrib[key] # 删除对应的属性
- 节点/元素 相关
删除子元素remove()
代码语言:javascript复制import xml.etree.ElementTree as ET
tree = ET.parse("country.xml")
root = tree.getroot() # 删除rank大于50的国家
for country in root.iter("country"):
rank = int(country.find("rank").text) if rank > 50: # remove()方法 删除子元素
root.remove(country)
ET.dump(root)
添加子元素
代码:
代码语言:javascript复制import xml.etree.ElementTree as ET
tree = ET.parse("country.xml")
root = tree.getroot()
country = root[0]
last_ele = country[len(list(country))-1]
last_ele.tail = 'ntt'
# 创建新的元素, tag为test_append
elem1 = ET.Element("test_append")
elem1.text = "elem 1"
# elem.tail = 'nt'
country.append(elem1) # SubElement() 其实内部调用的时append()
elem2 = ET.SubElement(country, "test_subelement")
elem2.text = "elem 2"
ET.dump(country)
添加子元素方法总结:
append
(subelement)extend
(subelements)insert
(index, element)
OK, 介绍了这么多,处理自己的jmeter脚本看看
代码语言:javascript复制try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
tree = ET.parse(r"C:Usersming.xieshDownloadslevel0.jmx") # <class 'xml.etree.ElementTree.ElementTree'>
root = tree.getroot() # 获取根节点 <Element 'data' at 0x02BF6A80>
key =[]
value=[]
for x in root.find("hashTree").find("hashTree").find("hashTree").find("Arguments").find("collectionProp").findall("elementProp"):
#print(x.attrib)
for y in x.findall("stringProp"):
if y.attrib['name']=="Argument.name":
print(y.text)
key.append(y.text)
if y.attrib['name'] == 'Argument.value':
print(y.text)
value.append(y.text)
if "xx" in y.text:
y.text = "qa.xx.com"
tree = ET.ElementTree(root)
tree.write(r"C:Usersming.xieshDownloadslevel1.jmx", encoding="utf-8", xml_declaration=True)
测试了一下,发现完全符合我的标准。
然而,我发现了jmeter运行是可以传入参数的。 JMeter 命令行通过-D来指定System Properties,类似于Jdk中我们用-D来指定一些系统属性,比如开启JMX远程监控。
在JMeter脚本中我们用__property()函数来获取,比如-Durl=172.16.3.219在测试计划中用
{__property(port),,}来获取;
脚本如下:
运行命令如下:
代码语言:javascript复制-JthreadCount=2 -Jcycle=2 -Durl=www.baidu.com -Dport=80 -n -t F:Jmeterpractiseqw_login.jmx -l F:Jmeterpractiseresult1.jtl
如上使用-J -D在运行前动态设置属性,可以用来控制测试计划的执行,在非GUI方式运行时还是比较方便的。
自然性能测试自动化时我们可以利用这些命令行参数来动态指定属性,不用再修改脚本了。 虽然来得有些迟,但是还是让我长见识了。再也不需要自己来处理参数了。
如何生成报告? 非GUI模式压测输出生成HTMl报告
- 基本命令格式:
`jmeter -n -t <test JMX file> -l <test log file> -e -o <Path to output folder>`
jmeter -n -t test.jmx -l test.jtl -e -o /report
# -n:以非GUI形式运行Jmeter
# -t:test.jmx 执行脚本路径
# -l:test.jtl 运行结果保存路径(.jtl)
# -e:在脚本运行结束后生成html报告
# -o:输出HTML报告的目录
之前考虑过每次执行命令都要先去目录下清空报告文件夹和jtl,还要敲命令,很烦,后来想了一个方法,那就是写一个bat,每次执行bat都自动去清空之前的报告,然后执行命令 命令如下:
代码语言:javascript复制 del /s /Q D:apache-jmeter-3.2binresult.jtl 删除result.jtl文件
rd /s /Q D:apache-jmeter-3.2binHttpReport 删除HttpReport文件夹
md D:apache-jmeter-3.2binHttpReport 重建HttpReport文件夹
这样就会在指定的文件夹看到报告了。
这个结果很漂亮,基本能满足要求。是在windows上获取的,可以在mac上却一直不成功,也不知道为什么,我重新安装了jmeter,仍然没有生成结果。