为了从grinder繁琐的script里解脱出来,决定压力测试平台改用JMeter。
以测试一个seam login功能为例。基本步骤如下
1. 自动为threadgroup生成request sampler
首先在workbench中加入http proxy server并开启,改browser设置通过http proxy server并访问测试网站的登入页面,之后输入测试账号登入。这时JMeter自动抓取requests,包括对其他resource例如图片,js等的request.这里我们只关心两个requests.一个是开启页面的,第二个是登入时的。所以保留这两个requests,其他统统删除。这个也可以通过在http proxy server中加exlusive filter来完成。
2.自动获取viewId
JSF让人火大的一个地方就是它隐藏在代码中的viewId, 在JSF1.2里,request中viewId不对立即会引发view can not be restored exception。而viewId在session里又是时常改变的。解决的方法是创造一个extractor,在每次request后parse 相应,分析出里面的viewId,具体实现可参考http://rfeest.blogspot.com/2008/02/jmeter-und-jsf.html
3.增加cookie manager
在threadgroup里添加http cookie manager来保持sessionId
这里是完整的testplan,因为request sampler是用proxy产生的,所以非常的冗长
<?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="2.1"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Testplan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="Benutzer definierte Variablen" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread-Gruppe" enabled="true"> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Schleifen-Controller (Loop Controller)" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <stringProp name="LoopController.loops">1</stringProp> </elementProp> <stringProp name="ThreadGroup.num_threads">1</stringProp> <stringProp name="ThreadGroup.ramp_time">1</stringProp> <longProp name="ThreadGroup.start_time">1234863597000</longProp> <longProp name="ThreadGroup.end_time">1234863597000</longProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <stringProp name="ThreadGroup.duration"></stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true"> <collectionProp name="CookieManager.cookies"/> <boolProp name="CookieManager.clearEachIteration">false</boolProp> </CookieManager> <hashTree/> <OnceOnlyController guiclass="OnceOnlyControllerGui" testclass="OnceOnlyController" testname="Once Only Controller" enabled="true"/> <hashTree> <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="/sd4/home.seam" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="HTTPSampler.domain">ws029</stringProp> <stringProp name="HTTPSampler.port">8080</stringProp> <stringProp name="HTTPSampler.protocol">http</stringProp> <stringProp name="HTTPSampler.contentEncoding">ISO-8859-1</stringProp> <stringProp name="HTTPSampler.path">/sd4/home.seam</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> <boolProp name="HTTPSampler.use_keepalive">true</boolProp> <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> <stringProp name="HTTPSampler.FILE_NAME"></stringProp> <stringProp name="HTTPSampler.FILE_FIELD"></stringProp> <stringProp name="HTTPSampler.mimetype"></stringProp> <stringProp name="HTTPSampler.monitor">false</stringProp> <stringProp name="HTTPSampler.embedded_url_re"></stringProp> </HTTPSampler> <hashTree> <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="Browser-derived headers" enabled="true"> <collectionProp name="HeaderManager.headers"> <elementProp name="Host" elementType="Header"> <stringProp name="Header.name">Host</stringProp> <stringProp name="Header.value">ws029:8080</stringProp> </elementProp> <elementProp name="Accept-Language" elementType="Header"> <stringProp name="Header.name">Accept-Language</stringProp> <stringProp name="Header.value">de</stringProp> </elementProp> <elementProp name="Accept" elementType="Header"> <stringProp name="Header.name">Accept</stringProp> <stringProp name="Header.value">*/*</stringProp> </elementProp> <elementProp name="User-Agent" elementType="Header"> <stringProp name="Header.name">User-Agent</stringProp> <stringProp name="Header.value">Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)</stringProp> </elementProp> <elementProp name="Accept-Encoding" elementType="Header"> <stringProp name="Header.name">Accept-Encoding</stringProp> <stringProp name="Header.value">gzip, deflate</stringProp> </elementProp> <elementProp name="UA-CPU" elementType="Header"> <stringProp name="Header.name">UA-CPU</stringProp> <stringProp name="Header.value">x86</stringProp> </elementProp> </collectionProp> </HeaderManager> <hashTree/> </hashTree> <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="/sd4/home.seam" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> <collectionProp name="Arguments.arguments"> <elementProp name="notloggedin:j_id113" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.name">notloggedin:j_id113</stringProp> <stringProp name="Argument.value">notloggedin:j_id113</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> <elementProp name="notloggedin:j_id113:j_id117" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.name">notloggedin:j_id113:j_id117</stringProp> <stringProp name="Argument.value">gu</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> <elementProp name="notloggedin:j_id113:j_id119" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.name">notloggedin:j_id113:j_id119</stringProp> <stringProp name="Argument.value">test</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> <elementProp name="notloggedin:j_id113:j_id121" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.name">notloggedin:j_id113:j_id121</stringProp> <stringProp name="Argument.value">Anmelden</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> <elementProp name="javax.faces.ViewState" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> <stringProp name="Argument.name">javax.faces.ViewState</stringProp> <stringProp name="Argument.value">${jsfViewState}</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain">ws029</stringProp> <stringProp name="HTTPSampler.port">8080</stringProp> <stringProp name="HTTPSampler.protocol">http</stringProp> <stringProp name="HTTPSampler.contentEncoding">ISO-8859-1</stringProp> <stringProp name="HTTPSampler.path">/sd4/home.seam</stringProp> <stringProp name="HTTPSampler.method">POST</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> <boolProp name="HTTPSampler.use_keepalive">true</boolProp> <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> <stringProp name="HTTPSampler.FILE_NAME"></stringProp> <stringProp name="HTTPSampler.FILE_FIELD"></stringProp> <stringProp name="HTTPSampler.mimetype"></stringProp> <stringProp name="HTTPSampler.monitor">false</stringProp> <stringProp name="HTTPSampler.embedded_url_re"></stringProp> </HTTPSampler> <hashTree> <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="Browser-derived headers" enabled="true"> <collectionProp name="HeaderManager.headers"> <elementProp name="Content-Type" elementType="Header"> <stringProp name="Header.name">Content-Type</stringProp> <stringProp name="Header.value">application/x-www-form-urlencoded</stringProp> </elementProp> <elementProp name="Host" elementType="Header"> <stringProp name="Header.name">Host</stringProp> <stringProp name="Header.value">ws029:8080</stringProp> </elementProp> <elementProp name="Accept-Language" elementType="Header"> <stringProp name="Header.name">Accept-Language</stringProp> <stringProp name="Header.value">de</stringProp> </elementProp> <elementProp name="Accept" elementType="Header"> <stringProp name="Header.name">Accept</stringProp> <stringProp name="Header.value">image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/x-silverlight, */*</stringProp> </elementProp> <elementProp name="User-Agent" elementType="Header"> <stringProp name="Header.name">User-Agent</stringProp> <stringProp name="Header.value">Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)</stringProp> </elementProp> <elementProp name="Accept-Encoding" elementType="Header"> <stringProp name="Header.name">Accept-Encoding</stringProp> <stringProp name="Header.value">gzip, deflate</stringProp> </elementProp> <elementProp name="Referer" elementType="Header"> <stringProp name="Header.name">Referer</stringProp> <stringProp name="Header.value">http://ws029:8080/sd4/home.seam</stringProp> </elementProp> <elementProp name="UA-CPU" elementType="Header"> <stringProp name="Header.name">UA-CPU</stringProp> <stringProp name="Header.value">x86</stringProp> </elementProp> <elementProp name="Pragma" elementType="Header"> <stringProp name="Header.name">Pragma</stringProp> <stringProp name="Header.value">no-cache</stringProp> </elementProp> </collectionProp> </HeaderManager> <hashTree/> </hashTree> </hashTree> <ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" 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>true</xml> <fieldNames>false</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor" enabled="true"> <stringProp name="RegexExtractor.useHeaders">false</stringProp> <stringProp name="RegexExtractor.refname">jsfViewState</stringProp> <stringProp name="RegexExtractor.regex"><input type="hidden" name="javax\.faces\.ViewState" id="javax\.faces\.ViewState" value="(.+?)" /></stringProp> <stringProp name="RegexExtractor.template">$1$</stringProp> <stringProp name="RegexExtractor.default"></stringProp> <stringProp name="RegexExtractor.match_number">0</stringProp> </RegexExtractor> <hashTree/> <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" 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>true</xml> <fieldNames>false</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> </hashTree> </hashTree> </hashTree> </jmeterTestPlan>