nGrinder 架构简介
nGrinder 的 Groovy 脚本使用指南(Groovy 脚本结构)
nGrinder 的 Groovy 脚本使用指南(Groovy maven 结构)
nGrinder 的 Groovy 脚本使用指南(导入 Groovy Maven 工程到 IntelliJ)
与Jython脚本不同,Groovy 脚本结构是基于JUnit的。原因是我们想尽可能的重用现有的 JUnit 经验。几个 IDE 已经集成了 JUnit 而且可以让用户直接运行测试用例。
先来看一个基础的 Groovy 脚本模板
import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.plugin.http.HTTPRequest
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import HTTPClient.HTTPResponse
/** * 这是一个使用 HTTP 插件的简单例子,显示一个通过 HTTP 协议的单页检索请求 * * 这个是 nGrinder 自动生成的脚本 * * @author ${userName} */
@RunWith(GrinderRunner)
class TestRunner {
public static GTest test;
public static HTTPRequest request;
// 这个方法每个进程只执行一次
@BeforeProcess
public static void beforeClass() {
test = new GTest(1,"${name}");
request = new HTTPRequest();
test.record(request);
grinder.logger.info("before process.");
}
// 这个方法每个线程执行一次
@BeforeThread
public void beforeThread() {
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
// 在测试停止之前,这个方法将持续执行下去
@Test
public void test(){
HTTPResponse result = request.GET("${url}");
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));
}
}
}
nGrinder 的 Groovy 测试用例需要使用 @RunWith(GroovyRunner) 注解进行注释。当你在 IDE 的 JUnit 运行器中运行这个脚本时,这个注解将使用 GroovyRunner 来控制 JUnit 的行为,同时将 grinder 的上下文绑定到 JUnit 上。被 @Test 注释的方法会被反复执行,正如你在上面所看到的,你可以使用 JUnit 的断言机制去对测试结果进行断言处理。如果断言失败,那么当前线程内的最后一个次测试将被认定为失败。
替代 JUnit 中的通用注解:“@BeforeClass @Before @AfterClass @After ”,nGrinder 中的 Groovy 测试用例使用它自己的注解来控制脚本行为。
注解 | 描述 | 应用范围 | 用例 |
---|---|---|---|
@BeforeProcess | 定义在进程被调用之前应执行的行为 | static method | 加载被线程共享的资源文件,定义 GTest 等 |
@AfterProcess | 定义在进程被终止之前应执行的行为 | static method | 关闭资源文件 |
@BeforeThread | 定义在每个线程被调用之前应执行的行为 | member method | 登录目标系统,建立线程内的一些值,例如,Cookie 处理 |
@AfterThread | 定义在每个线程被终止之前应执行的行为 | member method | 退出系统 |
@Before | 定义每个被 @Test 注解的方法被执行前应执行的行为 | member method | 对个被 @Test 注解的方法的共享逻辑、变量设置 |
@After | 定义每个被 @Test 注解的方法被执行后应执行的行为 | member method | 很少使用 |
@Test | 定义测试行为,被执行多次 | member method | 测试体 |
通过下图来说明执行流程:
在测试用例示例中,请仔细查看以下部分。
public static GTest test;
public static HTTPRequest request;
// 这个方法每个进程只执行一次
@BeforeProcess
public static void beforeProcess() {
test = new GTest(1,"test name");
request = new HTTPRequest();
test.record(request);
grinder.logger.info("before process.");
}
在被 @BeforeProcess 注释的方法中,它定义了 GTest 实例而且记录 HttpRequest 实例上的任何调用并保存在静态成员变量(request)中。 可以使用不同的名字定义多组 Gtest\HTTPRequest ,我还没有验证有什么好处,也许写插件时可以使用(以后再验证,有知道的朋友也请告知)
在一个测试用例类中,可以定义多个测试方法,只要在这些测试方法上使用 @Test 注解即可
@Test
public void testGoogle(){
HTTPResponse result = request.GET("http://www.google.com");
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));
}
}
@Test
public void testYahoo(){
HTTPResponse result = request.GET("http://www.yahoo.com");
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.",is(200));
}
}
然而,你应该知道 ngrinder 的 GroovyRunner 对每一个线程只创建一个测试用例对象,而不像 JUnit 那样为每个被 @Test 注释的方法创建单独的测试用例对象。所以,每个被 @Test 注释的方法可以共享成员变量,他们可以相互影响。在 nGrinder 测试用例中,被 @Test 注释的方法很可能依赖前一个被 @Test 注释的方法的执行结果。因此,如果你在成员变量中保存前一个测试方法的结果,那么下一个测试方法中就可以使用此变量,你可以轻松的实现测试依赖性。
private boolean googleResult;
@Test
public void testGoogle(){
googleResult = false;
HTTPResponse result = request.GET("http://www.google.com");
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.",is(200));
}
googleResult = true;
}
@Test
public void testYahoo(){
if (!googleResult) {
grinder.logger.warn("Just return. Because prev google test is Failed.");
return;
}
HTTPResponse result = request.GET("http://www.yahoo.com");
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.",is(200));
}
}
初略翻译,不准确的地方请多多指正
原文地址:http://www.cubrid.org/wiki_ngrinder/entry/groovy-script-structure