Gatling进行WebSocket测试是模拟从建立连接、收发消息到验证响应的完整长连接会话。
ws和connect
ws("操作名称") 用于创建一个 WebSocket 操作构建器。本身不建立连接,是后续 connect、sendText 等具体操作的开始,参数用于在报告中标识该操作。
真正的连接建立由 .connect("/path") 方法完成。它向配置的wsBaseUrl发起HTTP握手并升级为WebSocket连接。
建立连接通常有两种方式,带参数基础连接和命名连接。
基础连接和参数传递
这是最常见的方式,通常在scenario中直接使用。你可以通过查询字符串传递动态参数,这些参数可以来自会话(Session)。
Scala
.exec(
ws("建立聊天连接")
.connect("/chat?username=#{username}&token=#{authToken}")
)
命名连接
对于需要跨多个请求复用同一个物理连接,或在同一场景中管理多个并行 WebSocket 连接的复杂场景,可以使用命名连接。
通过 .wsName("connectionName") 为连接指定一个名称,后续操作通过同名ws引用该连接。
Scala
// 建立命名连接
.exec(ws("Connect", "myWs").connect("/socket"))
// 使用同一连接发送消息
.exec(ws("Send on myWs", "myWs").sendText("..."))

发送消息:sendText
.sendText("消息内容") 用于通过已建立的 WebSocket 连接向服务器发送文本消息。消息内容可以是静态字符串,也可以利用Gatling的EL(表达式语言)语法 #{variableName} 从会话中动态获取,从而模拟真实用户行为。
Scala
.exec(
ws("发送聊天消息")
.sendText("""{"type": "chat", "content": "Hello, I'm #{userId}!"}""")
)
验证响应:checkTextMessage和await
服务器返回的消息不会自动触发断言,必须使用check来验证。这是Gatling WebSocket测试中最重要的一步,用来确认系统行为是否正确。
主要模式是 "发送后等待并检查",通过 .await(timeout) 方法实现。
定义检查点
使用 ws.checkTextMessage("检查点名称") 创建一个针对文本消息的检查器,后接 .check() 方法定义具体的断言规则(如检查 JSON 路径、正则表达式等)。
Scala
val messageCheck = ws.checkTextMessage("验证服务端回复")
.check(
jsonPath("$.reply").is("Hello back!"),
jsonPath("$.status").saveAs("msgStatus") // 将值保存到会话,供后续使用
)
等待并执行检查
在sendText后链式调用 .await(timeout)(check1, check2...)。Gatling 会等待最多timeout时长,尝试将在此期间收到的下一条服务器消息和定义的检查点进行匹配。
Scala
.exec(
ws("发送并等待回复")
.sendText("""{"command": "ping"}""")
.await(5.seconds)(messageCheck) // 等待5秒内匹配 messageCheck
)
提示:checkTextMessage 的API在 Gatling 3.0 后发生了变化。在旧版本(如 2.3)中,check 方法可以直接链式调用在sendText之后,但新版本中必须使用await块来包裹检查。
协议的配置
要稳定地进行测试,需要在协议层面进行基础配置。
基础协议配置
HttpProtocol使用 .wsBaseUrl("ws://host:port") 设置WebSocket服务的基础地址。还可以配置重连策略、自动回复心跳等。
Scala
val httpProtocol = http
.baseUrl("http://localhost:8080")
.wsBaseUrl("ws://localhost:8080")
.wsReconnect // 启用自动重连
.wsMaxReconnects(3) // 最大重连次数
.wsAutoReplyTextFrame { // 自动回复特定心跳消息
case "ping" => "pong"
}
高并发和长连接
资源管理:WebSocket 是长连接,高并发下会长期占用文件描述符和内存。需监控测试客户端和服务器端的资源限制。
负载模型:对于连接保持时间长、消息发送间歇性强的场景(如聊天),使用 constantConcurrentUsers 或 rampConcurrentUsers 来模拟稳定的并发用户池,比单纯使用 rampUsers 更真实。
综合应用例子
下面的脚本综合了上述所有操作,模拟了一个简单的 WebSocket 聊天室用户行为:
Scala
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class WebSocketChatSimulation extends Simulation {
val httpProtocol = http
.wsBaseUrl("ws://localhost:9000")
.wsAutoReplyTextFrame { case "ping" => "pong" }
// 定义一个检查点,用于验证连接成功后服务器返回的欢迎消息
val connectCheck = ws.checkTextMessage("连接确认")
.check(jsonPath("$.msg").is("Welcome to chat!"))
// 定义一个检查点,用于捕获其他用户发送的聊天消息
val incomingMessageCheck = ws.checkTextMessage("新消息")
.check(jsonPath("$.from").saveAs("sender"),
jsonPath("$.text").saveAs("messageText"))
val scn = scenario("WebSocket Chat User")
.exec(http("获取凭证").get("/auth").check(jsonPath("$.token").saveAs("userToken")))
.pause(1)
// 1. 建立连接
.exec(ws("连接聊天室").connect("/chat?token=#{userToken}").await(2.seconds)(connectCheck))
.pause(1)
// 2. 发送第一条消息并等待回显
.exec(ws("发送问候语")
.sendText("""{"text": "大家好,我上线了!"}""")
.await(5.seconds)(
ws.checkTextMessage("回显检查").check(jsonPath("$.echo").exists)
))
// 3. 模拟循环:间歇性发送消息,并同时监听服务器推送的其他消息
.repeat(5) {
pause(3.seconds)
.exec(ws("发送随机消息").sendText("""{"text": "Current time is #{currentTime}"}"""))
// 此处的await会等待本次sendText的特定回复
.pause(2.seconds)
// 这个单独的await用于监听期间可能收到的其他消息(如别人发的)
.exec(ws("监听广播").await(3.seconds)(incomingMessageCheck))
}
// 4. 关闭连接
.exec(ws("断开连接").close)
setUp(
scn.inject(rampUsers(100).during(30.seconds))
).protocols(httpProtocol)
}
掌握 Gatling的ws/connect、sendText 和 checkTextMessage/await 的组合使用,是搭建Gatling WebSocket测试场景的关键,从简单场景开始,再慢慢增加并发和业务逻辑复杂度。