高手的存在,就是让服务10亿人的时候,你感觉只是为你一个人服务......

Loadrunner vs Ngrinder

目录
  1. 1. 参数化
    1. 1.1. File方式
      1. 1.1.1. sequential(顺序取值 )
      2. 1.1.2. Random (随机取值)
      3. 1.1.3. Unique (唯一性取值)
      4. 1.1.4. 同行取值
    2. 1.2. Date/Time 方式
    3. 1.3. Unique Number
    4. 1.4. Vuser ID
  2. 2. 事务
  3. 3. 关联
  4. 4. 检查点
  5. 5. 添加cookie
  6. 6. 添加header
  7. 7. 思考时间
  8. 8. 集合点
  9. 9. 运行时设置
  10. 10. 执行
  11. 11. 日志功能关闭
  12. 12. 关闭重定向

整理Loadrunner与Ngrinder的部分差异。


参数化

File方式

sequential(顺序取值 )

迭代方式 Loadrunner Ngrinder
Each Iteration
(每次迭代)
在参数列表中设置,按照参数化的数据顺序,依次取值,取到最后一行时继续从头开始取。迭代一次值改变一次,迭代内值不变。
变量声明:
public static List lineList //存放参数文件记录
public def custno
public def lineNumber = 0
读取文件,在BeforeProcess块中定义:
lineList = new File(“./resources/custno.dat”).readLines(“UTF-8”)
顺序取值,在@Before方法内部调用,减少代码在Test中的耗时:
lineNumber = lineNumber%(lineList.size()-1)+1 //考虑了0行是列名行的情况,实际值从第1行开始
custno = lineList.get(lineNumber)
Each Occurrence
(每次出现)
在参数列表中设置,按照参数化的数据顺序,一个一个的来取,取到最后一行时继续从头开始取。每次出现的值都不一样
变量声明:
public static List lineList //存放参数文件记录
public def custno
public def lineNumber = 0
读取文件,在BeforeProcess块中定义:
lineList = new File(“./resources/custno.dat”).readLines(“UTF-8”)
顺序取值,在Test块中各出现处插入如下程序:
lineNumber = lineNumber%(lineList.size()-1)+1 //考虑了0行是列名行的情况,实际值从第1行开始
custno = lineList.get(lineNumber)
Once(只取一次) 在参数列表中设置,实际只取第一行 lineNumber取固定值1

Random (随机取值)

迭代方式 Loadrunner Ngrinder
Each Iteration
(每次迭代)
在参数列表中设置,随机取值 变量声明:
public static List lineList //存放参数文件记录
public def custno
public def rowNumber
读取文件,在BeforeProcess块中定义:
lineList = new File(“./resources/custno.dat”).readLines(“UTF-8”)
随机取值,在某一个test中定义:
def rowNumbertemp = new Random().nextInt(lineList.size())
if(rowNumbertemp == 0) {
rowNumbertemp = 1
}
rowNumber = rowNumbertemp
custno = lineList.get(rowNumber) //在其他需要使用的地方直接用rowNumber参数
Each Occurrence
(每次出现)
在参数列表中设置,每次出现的值都不一样 在出现处插入如下程序:
def rowNumber = new Random().nextInt(lineList.size())
if(rowNumber == 0) {
rowNumber = 1
}
custno = lineList.get(rowNumber)
Once(只取一次) 在参数列表中设置,每个虚拟用户值不一样,但每次迭代取值都一样 在BeforeThread处插入如下程序:
def rowNumber = new Random().nextInt(lineList.size())
if(rowNumber == 0) {
rowNumber = 1
}
custno = lineList.get(rowNumber)

Unique (唯一性取值)

迭代方式 Loadrunner Ngrinder
Each Iteration
(每次迭代)
在参数列表中设置,结束策略有三种,分别为:1、AbortVuser;2、ContinueInCycleManner;3、ContinueWithLastValue。通过下拉框选择结束策略 参数文件第一行是标题
文件最后不留空行
编码实现唯一性取值,参考TestRunner.groovy的代码:
首先声明全局类变量
//声明类的全局变量
public static final List usernameList = new File(“./resources/username.txt”).readLines()
public def username
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}
private int invokeTimes = 0 //调用方法计数,不可随意修改
//迭代唯一取值方法
//update on Each Iteration
private int getCounterByIteration() {
assertTrue(grinder.runNumber >= 0)
int counter = getCounter(grinder.runNumber)
int line2 =counter + 1 ;
int MaxLine = usernameList.size() - 1;
WhenOutOfValues outHandler = WhenOutOfValues.AbortVuser
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}
//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Before方法内部调用,减少唯一值代码在Test中的耗时
int line = this.getCounterByIteration();
username = usernameList.get(line)

Each Occurrence
(每次出现)
在参数列表中设置,结束策略有三种,分别为:1、AbortVuser;2、ContinueInCycleManner;3、ContinueWithLastValue。通过下拉框选择结束策略 参数文件第一行是标题
文件最后不留空行
编码实现唯一性取值,参考TestRunner.groovy的代码:
首先声明全局类变量
//声明类的全局变量
public static final List usernameList = new File(“./resources/username.txt”).readLines()
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}
private int invokeTimes = 0 //调用方法计数,不可随意修改

//update on Each occurrrence
private int getCounterByOccurrence() {
int counter = getCounter(invokeTimes)
invokeTimes++
int line2 =counter + 1 ;
int MaxLine = usernameList.size() - 1;
WhenOutOfValues outHandler = WhenOutOfValues.AbortVuser
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}
//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Test方法内部各出现处调用
int line = this.getCounterByOccurrence();
String name = usernameList.get(line)

Once(只取一次) 在参数列表中设置,每个虚拟用户值不一样,但每次迭代取值都一样 参数文件第一行是标题
文件最后不留空行
编码实现唯一性取值,参考TestRunner.groovy的代码:
首先声明全局类变量
//声明类的全局变量
public static final List usernameList = new File(“./resources/username.txt”).readLines()
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}
private int invokeTimes = 0 //调用方法计数,不可随意修改
//迭代唯一取值方法
//update Once
private int getCounterByOnce() {
int counter = getCounter(0)
int line2 =counter + 1 ;
int MaxLine = usernameList.size() - 1;
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}

//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Before方法内部调用
int line = this.getCounterByOnce();
String name = usernameList.get(line)


同行取值

迭代方式 Loadrunner Ngrinder
同行取值 Select next row 记录选择方式Same line as 变量声明:
public static List cityLineList //存放参数文件记录
读取文件,在BeforeProcess块中定义:
cityLineList = new File(“./resources/City.txt”).readLines(“UTF-8”)
//x、y与city相关,需要同行取值,在Test方法内,city赋值处进行x、y的赋值
city = cityLineList.get(cityRowNumber).split(“,”)[1]
x = cityLineList.get(cityRowNumber).split(“,”)[5]
y = cityLineList.get(cityRowNumber).split(“,”)[4]

Date/Time 方式

迭代方式 Loadrunner Ngrinder
原始值 参数类型选择Date/Time
选择格式化字符串,例如
%Y-%m-%dT%H:%M:%S.000得到结果是
2017-10-31T16:27:10.993
在Test()出现处插入如下程序:
SimpleDateFormat formatter = new SimpleDateFormat(“dd-MM-yyyy HH:mm:ss:SSS”);
String formatStr =formatter.format(new Date());
//输出结果01-11-2017 16:51:11:251
可以指定不同的日期格式化字符串
时间偏移 日期时间参数,指定offset如增加1天和8小时,通过界面设置完成 在Test()出现处插入如下程序:
SimpleDateFormat formatter = new SimpleDateFormat(“dd-MM-yyyy HH:mm:ss:SSS”);
Date today = new Date()
Calendar c = Calendar.getInstance();
c.setTime(today);
c.add(Calendar.DAY_OF_MONTH, 1);// 今天+1天
c.add(Calendar.HOUR,8)//今天+8小时
Date tomorrow = c.getTime();
String formatStr =formatter.format(tomorrow);

Unique Number

迭代方式 Loadrunner Ngrinder
Each Iteration
(每次迭代)
参数类型设置为”Unique Number”
指定取值范围,范围默认1-100
超出范围后的方法可选:终止;循环;取最后一次的结果
private int invokeTimes = 0 //调用方法计数,不可随意修改
private jobId //全局变量,保存获取到的唯一值
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}

//迭代唯一取值方法
//update on Each Iteration
private int getCounterByIteration() {
assertTrue(grinder.runNumber >= 0)
int counter = getCounter(grinder.runNumber)
int line2 =counter + 1 ;
int MaxLine = 100;
WhenOutOfValues outHandler = WhenOutOfValues.AbortVuser
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}
//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Before方法内部调用,减少唯一值代码在Test中的耗时
int uniqueNumber = this.getCounterByIteration();
Each Occurrence
(每次出现)
参数类型设置为”Unique Number”
指定取值范围,范围默认1-100
超出范围后的方法可选:终止;循环;取最后一次的结果
编码实现唯一性取值,参考TestRunner.groovy的代码:

private int invokeTimes = 0 //调用方法计数,不可随意修改
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}
//update on Each occurrrence
private int getCounterByOccurrence() {
int counter = getCounter(invokeTimes)
invokeTimes++
int line2 =counter + 1 ;
int MaxLine = 100;
WhenOutOfValues outHandler = WhenOutOfValues.AbortVuser
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}
//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Test方法内部出现处调用
int uniqueNumber = this.getCounterByOccurrence();
Once(只取一次) 参数类型设置为”Unique Number”
指定取值范围,范围默认1-100
超出范围后的方法可选:终止;循环;取最后一次的结果
全局代码
private int invokeTimes = 0 //调用方法计数,不可随意修改
private jobId //全局变量,保存获取到的唯一值
private enum WhenOutOfValues {
AbortVuser, ContinueInCycleManner, ContinueWithLastValue
}
//update Once
private int getCounterByOnce() {
int counter = getCounter(0)
int line2 =counter + 1 ;
int MaxLine = 100;
if (line2 > MaxLine) {
if (outHandler.equals(WhenOutOfValues.AbortVuser)) {
grinder.stopThisWorkerThread()
} else if (outHandler.equals(WhenOutOfValues.ContinueInCycleManner)) {
line2 = (line2 - 1) % MaxLine + 1
} else if (outHandler.equals(WhenOutOfValues.ContinueWithLastValue)) {
line2 = MaxLine;
}
}
return line2
}
//取唯一值的计算方法
private int getCounter(int iteration){
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

int counter = agent_no intProcs intThreads + proc_no intThreads + thread_no + intAgents intProcs intThreads iteration
return counter
}
在@Before方法内部的代码
int number = this.getCounterByOnce();

Vuser ID

迭代方式 Loadrunner Ngrinder
Vuser ID 参数设置类型Vuser ID,从1开始的序号,所有用户不重复 声明VuserID为全局变量 public int VuserID=0;
放在before块中:
int intAgents = Integer.parseInt(grinder.getProperties().get(“grinder.agents”).toString())
int intProcs = Integer.parseInt(grinder.properties.get(“grinder.processes”).toString())
int intThreads = Integer.parseInt(grinder.properties.get(“grinder.threads”).toString())
int agent_no = grinder.agentNumber
int proc_no = grinder.processNumber
int thread_no = grinder.threadNumber

VuserID = agent_no intProcs intThreads + proc_no * intThreads + thread_no

事务

迭代方式 Loadrunner Ngrinder
实现方式 lr_start_transaction(“app_stats_page”);
lr_end_transaction(“app_stats_page”,LR_AUTO);
1、在类中定义事务:public static GTest test
2、在BeforeProcess方法体内进行事务初始化定义:test = new GTest(1, “Alluxio”)
3、在BeforeThread方法体内进行事务注册:test.record(this, “test”)
4、使用@Test标注分别定义方法名为test()的方法:
public void test(){}
事务嵌套 支持:
lr_start_transaction(“事务1”);
lr_start_transaction(“事务2”);
lr_end_transaction(“事务2);
lr_end_transaction(“事务1);
支持:
@Test
test1(){test2();}

test2(){}
执行顺序 多个事务之间顺序执行 导入包:
import org.junit.runners.MethodSorters
import org.junit.FixMethodOrder
在Class 前加
@FixMethodOrder(MethodSorters.NAME_ASCENDING),按照事务名的ASCII升序执行

关联

迭代方式 Loadrunner Ngrinder
关联 web_reg_save_param(“test”,
“LB=a”,
“RB=c”,
“NotFound=ERROR”,
“Search=Body”,
LAST);
—–备注:放置在请求发起之前
编写关联处理方法: public static String ngrinder_save_param(String paramName, String target, String lb, String rb, int ord, HTTPRequest request)
{
String[] param = StringUtils.substringsBetween(target, lb, rb);
String res = null;
if ((null != param) && (param.length > 0)) {
if (ord <= 0) {
res = param[0];
} else if ((ord > 0) && (ord <= param.length)) {
res = param[(ord - 1)];
} else {
res = param[(param.length - 1)];
}
}
request.setParam(paramName, res);

Grinder.grinder.getLogger().info(“打印关联输出: {}={}”, paramName, res);

return res;
} RecorderUtils.ngrinder_save_param(“item1”, result.text, “a”, “c”, 1, request)—–备注:1为关联到的第一个值,该函数放置在请求发起之后
将脚本中定义的参数名称,替换.json文件中对应的报文,形如${paramName}

检查点

迭代方式 Loadrunner Ngrinder
检查点 web_reg_find(“Fail=NotFound”,
“Search=All”,
“Text=success”,
LAST);
——-备注:放在请求之前
result = RecorderUtils.sendBy(request, requestJson.Test.REQ_3385)
assertTrue(result.text.contains(“需要匹配的内容”))
——备注:放在请求之后,检查body
assertThat(result.statusCode, is(200));——备注:检查状态码
assertTrue(result.Headers.contains(“需要匹配的内容”)) ——-备注:检查报头

添加cookie

迭代方式 Loadrunner Ngrinder
添加cookie web_add_cookie(“sessionId=3a6c25f17f6a477a6af59e66a3d541bb;DOMAIN=spmtest.cloudytrace.com”); // 在before中设置 cookie 信息,每个Test方法都能执行到
List cookieList = new ArrayList()
cookieList.add(new Cookie(“idsLoginUserIdLastTime”, “111222”, “www.test.com”, “/“, new Date(18503647599000L), false))
cookieList.add(new Cookie(“authId”, “si260114758005824C3B6DD9BD1AE4909F”, “www.test.com”, “/“, new Date(18503647599000L), false))
cookies = cookieList.toArray()
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }

添加header

迭代方式 Loadrunner Ngrinder
添加header web_add_header(“location”,
“bbb”);
方法一:直接在json报文中设定
方法二:在脚本中设定
List headerList = new ArrayList()
headerList.add(new NVPair(“User-Agent”, “nGrinder”))
headers = headerList.toArray()
request.setHeaders(headers)

思考时间

迭代方式 Loadrunner Ngrinder
思考时间 lr_think_time(1); sleep(1000)

集合点

迭代方式 Loadrunner Ngrinder
集合点 lr_rendezvous(“aaa”); 暂未实现

运行时设置

迭代方式 Loadrunner Ngrinder
设置长连接 支持设置长连接 不支持HTTP协议的长连接
模拟浏览器缓存 支持 不支持
下载非HTML资源 支持 支持,录制时的所有非HTML资源,在脚本中可以自主定义是否下载
每次迭代模拟一个新用户 支持 不支持
HTTP协议版本 支持HTTP1.0 HTTP1.1 支持HTTP1.0、HTTP1.1、HTTP1.2、HTTPS

执行

迭代方式 Loadrunner Ngrinder
按执行次数执行 总执行次数=虚拟用户数设置的执行次数事务数 平台总执行次数=虚拟用户数设置的执行次数事务数
按执行时间执行 最大支持99天23小时59分59秒 最大支持11小时59分59秒
多个脚本按百分比执行 支持 不支持
多个事务按百分比执行 不支持 导入import net.grinder.scriptengine.groovy.junit.annotation.RunRate;
在Test函数前加@RunRate(百分比)
脚本调试时执行多次 支持 导入import net.grinder.scriptengine.groovy.junit.annotation.Repeat;
在class前,@RunWith后添加@Repeat(次数)
虚拟用户启动 支持同时启动和每隔多少时间启动多少用户策略 支持
动态增加虚拟用户 支持 不支持
负载状态查看 只能看到状态机空闲、正常、繁忙状态,通过绿色、红、深红表示 能看到具体负载的CPU、内存消耗

日志功能关闭

迭代方式 Loadrunner Ngrinder
日志功能关闭 支持,在运行时设置中去勾选日志 导入jar包
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level
在beforeProcess中添加
LoggerFactory.getLogger(“worker”).setLevel(Level.ERROR);

关闭重定向

迭代方式 Loadrunner Ngrinder
关闭重定向 支持 HTTPPluginControl.getConnectionDefaults().setFollowRedirects(false)