Multi-Mechanize简介
Multi-Mechanize 是一个开源的性能和负载测试框架,它并发运行多个 Python 脚本对网站或者服务生成负载(组合事务)。测试输出报告保存为HTML或JMeter的兼容的XML。Multi-Mechanize最常用于web性能 和可扩展性(scalability)测试,也适用于任何python可以访问的API。尤其适合后台性能测试。稍微懂点编程的话,这个工具会远强过商业 的性能测试工具。
主要特性:
支持各种 HTTP methods
高级超链接和HTML表单支持
支持 SSL
自动处理 Cookies
可设置HTTP头
自动处理重定向
支持代理
支持 HTTP 认证
安装
使 用标准的python安装方式。注意,需要安装matplotlib以支持作图,在centos6下面可以这样安装yum -y install python27-matplotlib。multi-mechanize采用标准的python安装方式pip install multi-mechanize或者easy_install multi-mechanize这里都以linux(centos)为例。
centos 5 安装注意:
注意安装依赖: python26 python26-devel python26-numpy* python26-tornado
要EPEL支持: http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
快速入门
创建项目
# multimech-newproject my_project
执行项目
# multimech-run my_project
user_groups: 2
threads: 6
[================100%==================] 30s/30s transactions: 119 timers: 119 errors: 0
waiting for all requests to finish...
analyzing results...
transactions: 125
errors: 0
test start: 2013-09-13 11:47:47
test finish: 2013-09-13 11:48:16
created: ./my_project/results/results_2013.09.13_11.47.46/results.html
done.
如果有出现figure没有定义,请在相关文件的头部从matplotlib导入。
测试结果参见:
目录结构
每个测试项目包含以下内容:
config.cfg的配置文件。用于设定测试选项。
test_scripts/虚拟用户脚本的目录。在这里添加您的测试脚本。
results/:结果存储目录。对于每个测试都声称一个时间戳目录,里面包含结果的报告。
multimech-newproject,默认生成一个随机数的脚本。脚本v_user.py如下:
import randomimport timeclass Transaction(object):
def __init__(self):
pass
def run(self):
r = random.uniform(1, 2)
time.sleep(r)
self.custom_timers['Example_Timer'] = rif __name__ == '__main__':
trans = Transaction()
trans.run()
print trans.custom_timers
配置参数的含义如下:
run_time: duration of test (seconds) 测试的执行时间
rampup: duration of user rampup (seconds) 多少秒内发完请求
results_ts_interval: time series interval for results analysis (seconds) 结果分析时间
progress_bar: turn on/off console progress bar during test run 是否显示进度条
console_logging: turn on/off logging to stdout 是否输出到stdout
xml_report: turn on/off xml/jtl report 是否生成xml报告。
results_database: database connection string (optional) 保存结果的数据库连接字符串(可选)
post_run_script: hook to call a script at test completion (optional) 调用的善后脚本(可选)
更多介绍参见: http://testutils.org/multi-mechanize/configfile.html
脚本书写
用Python书写,测试脚本模拟虚拟用户对网站/服务/ API的请求,脚本定义了用户事务,更多内容参见脚本手册:http://testutils.org/multi-mechanize/scripts.html#scripts-label。
每个脚本必须实现一个Transaction()类。这个类必须实现一个run()方法。基本的测试脚本结构如下:
class Transaction(object):
def run(self):
# do something here
return
运行期间,Transaction()实例化一次,run()方法则反复调用:
class Transaction(object):
def __init__(self):
# do per-user user setup here
# this gets called once on user creation
return
def run(self):
# do user actions here
# this gets called repeatedly
return
从结构上看,如果每次run如果需要setup和teardown,时间也会计算在run里面,会显得事务处理的时间更长。这个就需要使用定时器来精确计时。
另外脚本建议先调试之后在运行,因为Multi-Mechanize有可能报错不够精准。可以这样运行:# python v_suds.py。v_suds.py是你实际使用的脚本名。另外suds这个库好像实现时性能一般,并发200时,客户端cpu占用率经常会100%,为此web service如果要上大量用户的话,建议用其他库替代,比如soapPy。进一步提升效率可以试用python的ctypes模块,或者cython(性能接近c语言)。不过Multi-Mechanize的多进程是基于python的,实在对性能有相当高的要求,就只能全部用c书写了。
下例使用mechanize进行web测试。
class Transaction(object):
def __init__(self):
pass
def run(self):
br = mechanize.Browser()
br.set_handle_robots(False)
resp = br.open('http://192.168.4.13/env.htm')
assert (resp.code == 200), 'Bad Response: HTTP %s' % resp.codes
assert ('service name' in resp.get_data())
下面用httplib库重写脚本,并增加定时器。通过定时器,可以分析各个步骤的耗时。
import httplib
import time
class Transaction(object):
def run(self):
conn = httplib.HTTPConnection('192.168.4.13')
start = time.time()
conn.request('GET', '/env.htm')
request_time = time.time()
resp = conn.getresponse()
response_time = time.time()
conn.close()
transfer_time = time.time()
self.custom_timers['request sent'] = request_time - start
self.custom_timers['response received'] = response_time - start
self.custom_timers['content transferred'] = transfer_time - start
assert (resp.status == 200), 'Bad Response: HTTP %s' % resp.status
if __name__ == '__main__':
trans = Transaction()
trans.run()
for timer in ('request sent', 'response received', 'content transferred'):
print '%s: %.5f secs' % (timer, trans.custom_timers[timer])
http://testutils.org/multi-mechanize/scripts.html#scripts-label 还有更多的实例。
import mechanize
import time
class Transaction(object):
def __init__(self):
pass
def run(self):
# create a Browser instance
br = mechanize.Browser()
# don't bother with robots.txt
br.set_handle_robots(False)
# add a custom header so wikipedia allows our requests
br.addheaders = [('User-agent', 'Mozilla/5.0 Compatible')]
# start the timer
start_timer = time.time()
# submit the request
resp = br.open('http://www.wikipedia.org/')
resp.read()
# stop the timer
latency = time.time() - start_timer
# store the custom timer
self.custom_timers['Load_Front_Page'] = latency
# verify responses are valid
assert (resp.code == 200), 'Bad Response: HTTP %s' % resp.code
assert ('Wikipedia, the free encyclopedia' in resp.get_data())
# think-time
time.sleep(2)
# select first (zero-based) form on page
br.select_form(nr=0)
# set form field
br.form['search'] = 'foo'
# start the timer
start_timer = time.time()
# submit the form
resp = br.submit()
resp.read()
# stop the timer
latency = time.time() - start_timer
# store the custom timer
self.custom_timers['Search'] = latency
# verify responses are valid
assert (resp.code == 200), 'Bad Response: HTTP %s' % resp.code
assert ('foobar' in resp.get_data()), 'Text Assertion Failed'
# think-time
time.sleep(2)
import urllib2
import time
class Transaction(object):
def run(self):
start_timer = time.time()
resp = urllib2.urlopen('http://www.example.com/')
content = resp.read()
latency = time.time() - start_timer
self.custom_timers['Example_Homepage'] = latency
assert (resp.code == 200), 'Bad Response: HTTP %s' % resp.code
assert ('Example Web Page' in content), 'Text Assertion Failed'
import urllib2
import time
class Transaction(object):
def __init__(self):
self.custom_timers = {}
with open('soap.xml') as f:
self.soap_body = f.read()
def run(self):
req = urllib2.Request(url='http://www.foo.com/service', data=self.soap_body)
req.add_header('Content-Type', 'application/soap+xml')
req.add_header('SOAPAction', 'http://www.foo.com/action')
start_timer = time.time()
resp = urllib2.urlopen(req)
content = resp.read()
latency = time.time() - start_timer
self.custom_timers['Example_SOAP_Msg'] = latency
assert (resp.code == 200), 'Bad Response: HTTP %s' % resp.code
assert ('Example SOAP Response' in content), 'Text Assertion Failed'
参考资料
本文涉及的python测试开发库 谢谢点赞!
- * 讨论 钉钉免费群21745728 qq群144081101 567351477