You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Groovy脚本获取MongoDB随机_id用于接口测试的报错求助

解决nGrinder Groovy脚本MongoDB依赖及编译错误问题

问题背景

我使用Groovy编写了基于nGrinder的接口测试脚本,userId已实现随机生成用于测试。现需将请求参数last_post_id(对应MongoDB的_id)也改为随机取值,实现思路是:1. 从MongoDB中获取所有_id并存入数组;2. 从数组中随机选取一个值。编写的脚本及运行时的编译错误如下:

原测试脚本

import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import 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.3
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

import org.ngrinder.http.HTTPRequest
import org.ngrinder.http.HTTPRequestControl
import org.ngrinder.http.HTTPResponse
import org.ngrinder.http.cookie.Cookie
import org.ngrinder.http.cookie.CookieManager

@Grapes([
    @Grab(group='org.mongodb', module='mongo-java-driver', version='3.12.12')
])
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import org.bson.Document;

/**
* 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 Map<String, String> headers = [:]
    public static Map<String, Object> params = [:]
    public static List<Cookie> cookies = []
    public static List<String> last_post_ids = []
    public static final String db_name = "instaclone_post"
    public static final String collection_name = "post"

    @BeforeProcess
    public static void beforeProcess() {
        HTTPRequestControl.setConnectionTimeout(300000)
        test = new GTest(1, "127.0.0.1")
        request = new HTTPRequest()
        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)
        CookieManager.addCookies(cookies)
        grinder.logger.info("before. init headers and cookies")
        
        def mongoClient = MongoClients.create("mongodb://localhost:27017")
        grinder.logger.info("before. create MongoClients")
        
        def collection = mongoClient.getDatabase(db_name).getCollection(collection_name)

        def documents = collection.find(new Document(), new Document("_id", 1)).into([])

        for (document in documents) {
            println(document.get("_id"))
            last_post_ids.add(document.get("_id"))
        }
    }

    @Test
    public void test() {
        int userId = Math.abs(new Random().nextInt() % 10) + 1
        Random rand = new Random();
        HTTPResponse response = request.GET("http://127.0.0.1:8030/feed-server/feed/" + {userId} + "?last_post_id=" + last_post_ids.nextInt(5), params)

        if (response.statusCode == 301 || response.statusCode == 302) {
            grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
        } else {
            assertThat(response.statusCode, is(200))
        }
    }
}

编译错误信息

unable to resolve class com.mongodb.MongoClient
 @ line 22, column 1.
   @Grapes([
   ^

unable to resolve class com.mongodb.client.MongoCollection
 @ line 26, column 1.
   import com.mongodb.client.MongoCollection;
   ^


unable to resolve class com.mongodb.client.MongoCursor
 @ line 27, column 1.
   import com.mongodb.client.MongoCursor;
   ^

unable to resolve class org.bson.Document
 @ line 28, column 1.
   import org.bson.Document;
   ^

unable to resolve class HTTPRequest
 @ line 60, column 2.
        public static HTTPRequest request
    ^

unable to resolve class Cookie
 @ line 63, column 21.
        public static List<Cookie> cookies = []
                       ^

unable to resolve class HTTPRequest
 @ line 72, column 13.
                request = new HTTPRequest()
               ^

 HTTPResponse response = request.GET("http://127.0.0.1:8030/feed-server/feed/" + {userId} + "?last_post_id=" + last_post_ids.nextInt(5), params)
                  ^

8 errors

        at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:295)
        at org.codehaus.groovy.control.CompilationUnit$ISourceUnitOperation.doPhaseOperation(CompilationUnit.java:914)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:627)
        at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:389)
        at groovy.lang.GroovyClassLoader.lambda$parseClass$3(GroovyClassLoader.java:332)
        at org.codehaus.groovy.runtime.memoize.StampedCommonCache.compute(StampedCommonCache.java:163)
        at org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(StampedCommonCache.java:154)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:330)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:314)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:244)
        at net.grinder.scriptengine.groovy.GroovyScriptEngine.<init>(GroovyScriptEngine.java:64)

修复方案及修正后的脚本

核心修复点

  • MongoDB依赖处理:nGrinder环境下@Grab注解通常无法自动拉取依赖,需手动下载mongo-java-driver-3.12.12.jar及其依赖的bson-3.12.12.jar,放入nGrinder安装目录的lib文件夹下,重启nGrinder服务。
  • Mongo客户端初始化修正:3.12.12版本的驱动使用MongoClient而非MongoClients,需修改初始化代码。
  • 数据加载时机调整:将MongoDB数据加载移到BeforeThread中,避免每次用例执行都重复查询数据库,提升性能。
  • 随机取值代码修正:使用Random类生成数组索引,随机获取last_post_id。
  • 字符串拼接修正:移除闭包写法{userId},直接使用变量拼接。
  • 导入Random类:添加java.util.Random的导入,避免编译错误。

修正后的完整脚本

import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.script.GTest
import net.grinder.script.Grinder
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 java.util.Random

import org.ngrinder.http.HTTPRequest
import org.ngrinder.http.HTTPRequestControl
import org.ngrinder.http.HTTPResponse
import org.ngrinder.http.cookie.Cookie
import org.ngrinder.http.cookie.CookieManager

import com.mongodb.MongoClient
import com.mongodb.client.MongoCollection
import org.bson.Document

/**
* nGrinder接口测试脚本:随机获取MongoDB中的post_id作为请求参数
*
* @author admin
*/
@RunWith(GrinderRunner)
class TestRunner {

    public static GTest test
    public static HTTPRequest request
    public static Map<String, String> headers = [:]
    public static Map<String, Object> params = [:]
    public static List<Cookie> cookies = []
    public static List<String> last_post_ids = []
    public static final String db_name = "instaclone_post"
    public static final String collection_name = "post"
    public static Random rand = new Random()

    @BeforeProcess
    public static void beforeProcess() {
        HTTPRequestControl.setConnectionTimeout(300000)
        test = new GTest(1, "127.0.0.1")
        request = new HTTPRequest()
        grinder.logger.info("before process.")
    }

    @BeforeThread
    public void beforeThread() {
        test.record(this, "test")
        grinder.statistics.delayReports = true
        grinder.logger.info("before thread.")
        
        // 线程初始化时查询一次MongoDB,避免每次用例重复查询
        MongoClient mongoClient = new MongoClient("localhost", 27017)
        grinder.logger.info("Connected to MongoDB successfully")
        
        MongoCollection<Document> collection = mongoClient.getDatabase(db_name).getCollection(collection_name)
        def documents = collection.find(new Document(), new Document("_id", 1)).into([])
        
        for (document in documents) {
            def postId = document.get("_id").toString()
            last_post_ids.add(postId)
            grinder.logger.info("Loaded post_id: {}", postId)
        }
        
        mongoClient.close()
    }

    @Before
    public void before() {
        request.setHeaders(headers)
        CookieManager.addCookies(cookies)
        grinder.logger.info("before. init headers and cookies")
    }

    @Test
    public void test() {
        // 生成随机userId
        int userId = Math.abs(rand.nextInt() % 10) + 1
        
        // 随机获取last_post_id
        String lastPostId = last_post_ids.isEmpty() ? "" : last_post_ids.get(rand.nextInt(last_post_ids.size()))
        
        // 拼接请求URL
        String url = "http://127.0.0.1:8030/feed-server/feed/${userId}?last_post_id=${lastPostId}"
        HTTPResponse response = request.GET(url, params)

        if (response.statusCode == 301 || response.statusCode == 302) {
            grinder.logger.warn("Warning. The response code was {}.", response.statusCode)
        } else {
            assertThat(response.statusCode, is(200))
        }
    }
}

内容的提问来源于stack exchange,提问作者happy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 09:07:02