2013-09-13 磁针石
#承接软件自动化实施与培训等gtalk:ouyangchongwu#gmail.comqq 37391319
#博客:http://blog.csdn.net/oychw
#版权所有,转载刊登请来函联系
# 深圳测试自动化python项目接单群113938272深圳广州软件测试开发 6089740
#深圳湖南人业务户外群 66250781武冈洞口城步新宁乡情群49494279
#参考资料:python手册
Multi-Mechanize 是一个开源的性能和负载测试框架,它并发运行多个 Python 脚本对网站或者服务生成负载(组合事务)。
Multi-Mechanize最常用于web性能和可扩展性(scalability)测试,也适用于任何python可以访问的API。
测试输出报告保存为HTML或JMeter的兼容的XML。主要特性:
使用标准的python安装方式。注意,需要安装matplotlib以支持作图,在centos6下面可以这样安装yum -y install python27-matplotlib。这里都以linux(centos)为例。
创建项目:# 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 tofinish...
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.
至此,我们已经完成了一个简单的性能测试。
查看性能测试结果:./my_project/results/results_2013.09.13_11.47.46/results.html
transactions: 125
errors: 0
run time: 30 secs
rampup: 0 secs
test start: 2013-09-1311:47:47
test finish: 2013-09-1311:48:16
time-series interval: 10secs
workload configuration:
group name |
threads |
script name |
user_group-1 |
3 |
v_user.py |
user_group-2 |
3 |
v_user.py |
count |
min |
avg |
80pct |
90pct |
95pct |
max |
stdev |
125 |
1.021 |
1.499 |
1.796 |
1.890 |
1.972 |
2.002 |
0.282 |
interval |
count |
rate |
min |
avg |
80pct |
90pct |
95pct |
max |
stdev |
1 |
43 |
4.30 |
1.021 |
1.462 |
1.688 |
1.841 |
1.897 |
2.002 |
0.263 |
2 |
39 |
3.90 |
1.026 |
1.543 |
1.830 |
1.934 |
1.976 |
1.986 |
0.290 |
3 |
37 |
3.70 |
1.025 |
1.495 |
1.806 |
1.964 |
1.985 |
1.988 |
0.295 |
count |
min |
avg |
80pct |
90pct |
95pct |
max |
stdev |
119 |
1.020 |
1.497 |
1.794 |
1.889 |
1.970 |
2.000 |
0.281 |
interval |
count |
rate |
min |
avg |
80pct |
90pct |
95pct |
max |
stdev |
1 |
43 |
4.30 |
1.020 |
1.461 |
1.686 |
1.839 |
1.895 |
2.000 |
0.262 |
2 |
39 |
3.90 |
1.025 |
1.542 |
1.828 |
1.932 |
1.975 |
1.984 |
0.289 |
3 |
37 |
3.70 |
1.024 |
1.493 |
1.804 |
1.962 |
1.983 |
1.986 |
0.295 |
每个测试项目包含以下内容:
config.cfg的配置文件。用于设定测试选项。
test_scripts/虚拟用户脚本的目录。在这里添加您的测试脚本。
results/:结果存储目录。对于每个测试都声称一个时间戳目录,里面包含结果的报告。
multimech-newproject,默认生成一个随机数的脚本。脚本如下:
# cat v_user.py
import random
import time
class Transaction(object):
def__init__(self):
pass
defrun(self):
r= random.uniform(1, 2)
time.sleep(r)
self.custom_timers['Example_Timer'] = r
if __name__ == '__main__':
trans= Transaction()
trans.run()
print trans.custom_timers
配置参数的含义如下:
特别提下 rampup表示多长时间内加载完所有用户。详细的配置参见: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。
下例使用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), 'BadResponse: HTTP %s' % resp.codes
assert ('service name' inresp.get_data())
下面用httplib库重写脚本,并增加定时器。通过定时器,可以分析各个步骤的耗时。
import httplib
import time
class Transaction(object):
defrun(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()
fortimer 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还有更多的实例:
importmechanize
importtime
classTransaction(object):
def__init__(self):
pass
defrun(self):
# create a Browserinstance
br = mechanize.Browser()
# don't bother withrobots.txt
br.set_handle_robots(False)
# add a customheader so wikipedia allows our requests
br.addheaders = [('User-agent', 'Mozilla/5.0Compatible')]
# start the timer
start_timer= time.time()
# submit therequest
resp = br.open('http://www.wikipedia.org/')
resp.read()
# stop the timer
latency = time.time() - start_timer
# store the customtimer
self.custom_timers['Load_Front_Page'] = latency
# verify responsesare valid
assert (resp.code ==200), 'Bad Response: HTTP%s'% resp.code
assert ('Wikipedia, thefree 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 customtimer
self.custom_timers['Search'] = latency
# verify responsesare valid
assert (resp.code ==200), 'Bad Response: HTTP%s'% resp.code
assert ('foobar'in resp.get_data()), 'Text AssertionFailed'
# think-time
time.sleep(2)
importurllib2
importtime
classTransaction(object):
defrun(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 AssertionFailed'
importurllib2
importtime
classTransaction(object):
def__init__(self):
self.custom_timers = {}
withopen('soap.xml') as f:
self.soap_body = f.read()
defrun(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 SOAPResponse'in content), 'Text AssertionFailed'
importhttplib
importurllib
importtime
classTransaction(object):
def__init__(self):
self.custom_timers = {}
defrun(self):
post_body=urllib.urlencode({
'USERNAME': 'corey',
'PASSWORD': 'secret',})
headers = {'Content-type': 'application/x-www-form-urlencoded'}
start_timer= time.time()
conn = httplib.HTTPConnection('www.example.com')
conn.request('POST', '/login.cgi', post_body, headers)
resp = conn.getresponse()
content = resp.read()
latency = time.time() - start_timer
self.custom_timers['LOGIN'] = latency
assert (resp.status ==200), 'Bad Response: HTTP%s'% resp.status
assert ('Example Web Page'in content), 'Text AssertionFailed'
参考资料:
http://testutils.org/multi-mechanize/