ngrinder 压力测试实践(二)groovy 脚本实战
ngrinder 的进程与线程ngrinder 的 groovy 脚本是顺序结构的,用户可通过编写脚本执行过程中被预置的函数进行用户操作,完成各种复杂的测试工作。
ngrinder 使用进程和线程来模拟多个用户。例如,如果您设置了如下的测试。只有一个代理将被激活,1个进程将被调用,然后这个进程将包括2个运行线程。每个线程的行为就像1个用户。因此,2个虚拟用户正在运行。如果将代理计数增加到2,则总共有4个虚拟用户(Vusers)。
并发量=代理数x进程数x线程数
官方最新测试:4G内存的agent 最多可以模拟4000 虚拟用户。
如果在Vuser per agent 中输入总的虚拟用户数时,nGrinder根据内部算法,会进行适当的计算,如输入100,当agent数为1时, 会变成99,该算法可以通过 process_and_thread_policy.js 这个文件来修改。
若果agent 的内存4G以下的话,建议进程不要超过10个,线程数不要超过200.
预置函数
依据上面对agent、进程与线程的解释,就比较好理解ngrinder groovy 脚本的
结构了。
控制器将脚本分发给agent,每个agent按照算法启动对应数量的进程,每个进程里在启动对应数量的线程,执行测试任务。
groovy 脚本实例
压测实例
/*这个脚本是对需要验签接口的压测*/import static net.grinder.script.Grinder.grinderimport static org.junit.Assert.*import static org.hamcrest.Matchers.*import net.grinder.plugin.http.HTTPRequestimport net.grinder.plugin.http.HTTPPluginControlimport net.grinder.script.GTestimport net.grinder.script.Grinderimport net.grinder.scriptengine.groovy.junit.GrinderRunnerimport net.grinder.scriptengine.groovy.junit.annotation.BeforeProcessimport net.grinder.scriptengine.groovy.junit.annotation.BeforeThread// import static net.grinder.util.GrinderUtils.* // You can use this if you're using nGrinder after 3.2.3import org.junit.Beforeimport org.junit.BeforeClassimport org.junit.Testimport org.junit.runner.RunWithimport java.util.Dateimport java.util.Listimport java.util.ArrayListimport org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level;import HTTPClient.Cookieimport HTTPClient.CookieModuleimport HTTPClient.HTTPResponseimport HTTPClient.NVPairimport java.text.SimpleDateFormat;import org.apache.commons.codec.binary.Base64;import java.security.spec.PKCS8EncodedKeySpec;import java.security.KeyFactory;import java.security.PrivateKey;import java.security.Signature;import java.util.Arrays;import org.apache.commons.lang.StringUtils;import java.lang.StringBuilderimport java.io.UnsupportedEncodingException;/** * A simple example using the HTTP plugin that shows the retrieval of a * single page via HTTP. * * This script is automatically generated by ngrinder. * * @author admin */@RunWith(GrinderRunner)class TestRunner { public static GTest test public static HTTPRequest request // 定义全局变量 public static NVPair[] params = [] public static Cookie[] cookies = [] public static String private_key public static String[] contents = [] @BeforeProcess public static void beforeProcess() { HTTPPluginControl.getConnectionDefaults().timeout = 6000 test = new GTest(1, "Test1") request = new HTTPRequest() // 获取加密私钥内容 contents = new File("./resources/rsa_private_key_pkcs8.pem") as String[] StringBuilder private_str = new StringBuilder(); for(int i=0;i<contents.length;i++){ if (contents[i].charAt(0) != '-' && contents[i] != null) { private_str.append(contents[i]).append("\n"); } } private_key = private_str.toString() //调试输出 grinder.logger.info("before process."); } @BeforeThread public void beforeThread() { test.record(this, "test") grinder.statistics.delayReports=true; grinder.logger.info("before thread."); } //自定义函数,修改http头数据 private NVPair[] headers(post) { if( post != null ){ post="&"+post }else{ post="" } def appid = "1111111111111111111111" def appcode = "11111" long currentTime = System.currentTimeMillis() def json = "appId="+appid+"&appCode="+appcode+"&"+""+"timestamp="+currentTime+post def sign = getsign(json) //grinder.logger.info(currentTime.toString()) return [ new NVPair("Content-type", "application/json;charset=UTF-8"), new NVPair("appId", "1013f9d4e97026cb07e3fdea1b560f2f"), new NVPair("sign", sign), new NVPair("timestamp", currentTime.toString()), new NVPair("appCode", "11111") ]; } //自定义函数,生成YYYY-MM-dd HH:mm:ss 格式的当天日期串 def today() { String str = ""; SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); Calendar lastDate = Calendar.getInstance(); str = sdf.format(lastDate.getTime()); return str; } // 自定义函数加签 private getsign(post){ //加签算法 略 return sign } @Before public void before() { request.setHeaders(headers()) cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) } grinder.logger.info("before thread. init headers and cookies"); } @Test public void test(){ // 参数初始化 def domain = "api.xxxx.com" def timestr=today() def json='{"eventCode":"1111111", "eventTime":"'+timestr+'", "channelCode":"1111111" , eventTime":"'+timestr+'"}}'; //获取签名后的头信息 def head = headers("bizContent="+json) //grinder.logger.info(head.toString()) HTTPResponse result = request.POST('http://'+domain+'/channel/v1/receive',json.getBytes(), head) //HTTPResponse result = request.GET("http://10.14.8.111/phpapi.php", params) if(result.text.equals(new String(result.text.getBytes("iso8859-1"), "iso8859-1"))) { result.text=new String(result.text.getBytes("iso8859-1"),"utf-8"); } //调试输出头信息 grinder.logger.info("result="+request.getHeaders()) //调试输出结果数据 grinder.logger.info("result="+result.text) if (result.statusCode == 301 || result.statusCode == 302) { grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode); } else { assertThat(result.statusCode, is(200)); } }}
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。