nGrinder
nGrinder简介
nGrinder是一个压力测试平台,使您可以同时执行脚本创建,测试执行,监视和结果报告生成器。开源nGrinder通过消除不便并提供集成环境,提供简单的方法来进行压力测试。
特征
- 使用Jython或Groovy脚本创建测试场景并使用多个代理在JVM中生成压力。
- 使用自定义库(jar,py,maven依赖项)扩展测试。它是无限的。
- 为项目管理,监控,结果管理和报告管理提供基于Web的界面。
- 在IDE中开发和测试Groovy脚本,并在分布式代理中运行它。
- 同时运行多个测试。分配预先安装的多个代理以最大化每个代理的利用率。
- 在多个网络区域上部署代理。在各种网络位置执行测试
- 嵌入Subversion来管理脚本。
- 允许监控产生压力的代理状态和接收压力的目标机器
- 经过验证的解决方案,用于测试拥有超过1亿用户的大型系统。
下载
您可以通过以下链接下载最新版本
文档
您可以在以下链接中找到安装指南。
您可以在以下链接中找到用户指南。
总体架构
nGrinder 是一款在一系列机器上执行 Groovy 或 Jython 测试脚本的应用,内部引擎是基于 Grinder。 nGrinder 使用 controller 和 agent 分别包装了 Grinder 的 console 和 agent ,而且扩展了多种功能使其能够支持并发测试。
组件介绍
Controller
- 提供性能测试的web接口。
- 协调测试进程。
- 整理和显示测试的统计结果
- 让用户创建和修改脚本。
- nGrinder 从 3.1 版本开始支持 controller 集群
主要就是我们下载的war包使用tomcat容器运行的平台 ,相当于前端控制器。
Agent
- 在代理服务器上加载运行测试进程和线程
- 监控目标机器的系统性能(例如:CPU/MEMORY)
由前端控制器操作实际支配的肉鸡,命运较惨,主要执行前端控制器下达的各种任务。
运行在肉鸡系统中有一定先决条件,需要安装Jdk1.8;
测试服务器安装Controller
- 在下载地址下载最新版本ngrinder-controller-3.4.2.war
- 修改war包名称为ngrinder(或者其他 你开心就好)
- 准备tomcat运行环境服务器、保证安装Jdk1.8和tomcat 并正常运行。
- 将ngrinder.war包拷贝至服务器tomcat下/webhapps目录下
- 启动tomcat服务器
- 访问http://localhost:8080/ngrinder
测试肉鸡服务器安装Agent
- 准备Agent肉鸡服务器 若干台需要安装Jdk1.8;
- 登录Controller控制器网站登录
- 用户名下展开后点击下载Agent(代理)
- 将Agent代理拷贝至肉鸡服务器
- 解压缩后运行run.agent.bat.
被测服务器安装Monitor
- Agent服务器安装好Agent后是不需要安装Monitor的自动集成了
- 需要在被测试的机器中安装Monitor以监控在测试期间被测服务器的性能表现;
- 登录Controller控制器网站登录、用户下展开后点击下载监控(Monitor)
- 拷贝至被测试服务器运行run.monitor.bat
快速入门测试
- 登录系统后有个快速开始的框,在此输入http://www.baidu.com,点击开始测试。
- 这时候进入第二个页面配置运行参数 agent(?需要几台机器) 持续多长时间
- 点击保存并开始,立即运行;
- 查看运行后的测试报告;
脚本开发介绍
import HTTPClient.Cookie
import HTTPClient.CookieModule
import HTTPClient.HTTPResponse
import HTTPClient.NVPair
import net.grinder.plugin.http.HTTPPluginControl
import net.grinder.plugin.http.HTTPRequest
import net.grinder.script.GTest
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import static net.grinder.script.Grinder.grinder
import static org.hamcrest.Matchers.is
import static org.junit.Assert.assertThat
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test
public static HTTPRequest request
public static NVPair[] headers = []
public static NVPair[] params = []
public static Cookie[] cookies = []
@BeforeProcess
public static void beforeProcess() {
HTTPPluginControl.getConnectionDefaults().timeout = 6000
test = new GTest(1, "www.baidu.com")
request = new HTTPRequest()
// 设置请求头数据
List<NVPair> headerList = new ArrayList<NVPair>()
headerList.add(new NVPair("test_header", "test_header_value"))
headers = headerList.toArray()
// 设置请求参数
List<NVPair> paramList = new ArrayList<NVPair>()
paramList.add(new NVPair("paramname", "vaule"))
params = paramList.toArray()
// 设置 cookie 信息
List<Cookie> cookieList = new ArrayList<Cookie>()
cookieList.add(new Cookie("username", "testname", "www.baidu.com", "/", new Date(), false))
cookies = cookieList.toArray()
// 记录日志
grinder.logger.info("before process.")
}
@BeforeThread
public void beforeThread() {
test.record(this, "test")
// 配置延迟报告统计结果
grinder.statistics.delayReports = true
// 记录日志
grinder.logger.info("before thread.")
}
@Before
public void before() {
// 设置本次请求头
request.setHeaders(headers)
// 设置本次请求的 cookies
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
// 记录日志
grinder.logger.info("before thread. init headers and cookies")
}
@Test
public void test() {
HTTPResponse result = request.GET("http://www.baidu.com", params)
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))
}
}
}
静态变量说明
public static GTest test
public static HTTPRequest request
public static NVPair[] headers = []
public static NVPair[] params = []
public static Cookie[] cookies = []
- 定义 GTest 静态变量
test
- 定义 HTTPRequest 静态变量
request
,用于发送 HTTP 请求 - 定义 NVPair 数组
headers
,用于存放通用的请求头数据 - 定义 NVPair 数组
params
,用于存放请求参数数据 - 定义 Cookie 数组
cookies
,用于存放通用的 cookie 数据
初始化进程级数据
使用 @BeforeProcess
注释的方法,定义了在 进程 被调用之前应执行的行为
@BeforeProcess
public static void beforeProcess() {
// HTTP请求超时时间,单位毫秒
HTTPPluginControl.getConnectionDefaults().timeout = 6000
test = new GTest(1, "www.baidu.com")
request = new HTTPRequest()
// 设置请求头数据
List<NVPair> headerList = new ArrayList<NVPair>()
headerList.add(new NVPair("test_header", "test_header_value"))
headers = headerList.toArray()
// 设置请求参数
List<NVPair> paramList = new ArrayList<NVPair>()
paramList.add(new NVPair("paramname", "vaule"))
params = paramList.toArray()
// 设置 cookie 信息
List<Cookie> cookieList = new ArrayList<Cookie>()
cookieList.add(new Cookie("username", "testname", "www.baidu.com", "/", new Date(), false))
cookies = cookieList.toArray()
// 记录日志
grinder.logger.info("before process.")
}
- 首先设置了HTTP请求超时时间,单位毫秒.
- GTest是对测试记录进行统计的单元,脚本内,每个 GTest 对象都使用唯一的编号定义,可以有描述信息,使用 GTest 的构造方法
GTest(int number, String description)
创建。如果创建了多个编号一样的对象,最后只会选用第一个 - 使用
new HTTPRequest()
创建 HTTPRequest 对象,用于发起 HTTP 请求 - 请求头和请求参数,都是键值对对象 NVPair 类型的数组
- 可以通过
Cookie(String name, String value, String domain, String path, Date expires, boolean secure)
构造 cookie 对象,然后存放到相应的数组中,方便后面使用 - 最后打印了执行日志
初始化线程级数据
使用 @BeforeThread
注释的方法,定义了在 线程 被调用之前应执行的行为
@BeforeThread
public void beforeThread() {
test.record(this, "test")
// 配置延迟报告统计结果
grinder.statistics.delayReports = true
// 记录日志
grinder.logger.info("before thread.")
}
- 使用 GTest 的
record(Object target, String methodName)
给 GTest 配置需要进行统计的方法,target 只脚本对象,这里是 this, methodName 是需要统计的方法名,通常都是被 @Test 注释的方法。如果未配置,方法会正常执行,但是没有统计结果数据,每一个被 @Test 注释的方法都是一个整体事务,在运行测试时,即便里面有 多次 HTTP 请求也只做一次统计。 - 配置延迟报告统计结果
- 最后打印了执行日志
初始化测试级别数据
使用 @Before
注释的方法,定义每个被 @Test 注解的方法被执行前应执行的行为
@Before
public void before() {
// 设置本次请求头
request.setHeaders(headers)
// 设置本次请求的 cookies
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
// 记录日志
grinder.logger.info("before thread. init headers and cookies")
}
- 设置本次请求头
- 设置本次请求的 cookies
- 最后打印了执行日志
定义测试行为
使用 @Test
注释的方法,定义测试行为,被执行多次
@Test
public void test() {
// 发起 GET 请求
HTTPResponse result = request.GET("http://www.baidu.com", params)
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))
}
}
- 通过
request.GET
方法发起 HTTP 的 GET 请求,也可以使用它的重载方法,在次数执行请求头 - 根据请求的返回结果分别进行处理,如果是 HTTP 的返回状态码为重定向,则打日志,当然您可以做其他处理,否则,使用断言
assertThat
方法进行结果验证,会自动进入统计结果中。 HTTPRequest
对象还有其他的请求方法:POST
,PUT
,DELETE
等。