如何在Citrus框架多测试类中传递负载提取变量及使用TestContext?
嘿,我来帮你搞定Citrus框架里跨测试类共享auth-token的问题,顺便理清TestContext的用法~
解决Citrus框架跨类共享Auth-Token的问题
一、先搞懂TestContext的作用
每个Citrus测试类都会有自己的TestContext,它是当前测试实例的私有变量容器,用来存储提取的参数、测试数据、状态信息等。默认情况下这个上下文只能在当前测试类里用,要跨类共享token,就得把变量转移到全局可访问的存储里。
二、预测试步骤:把Token存入全局/共享容器
你的GetTokenIT已经能正确从响应头和 payload 里提取token了,现在要做的是把这些token从当前TestContext转移到全局可访问的地方,这里有两种常用方式:
方式1:用Citrus自带的全局变量
Citrus提供了全局变量存储池,所有测试类都能访问。修改你的GetTokenIT代码:
import com.consol.citrus.annotations.CitrusTest; import com.consol.citrus.testng.TestNGCitrusTest; import org.testng.annotations.BeforeSuite; @BeforeSuite // 这个注解确保在所有测试套件启动前执行 public class GetTokenIT extends TestNGCitrusTest { @CitrusTest public void fetchAuthToken() { http() .client(HttpTqaClient) .receive() .response(HttpStatus.OK) .messageType(MessageType.JSON) .extractFromHeader("Authorization", "header_token") .extractFromPayload("$.id_token", "payload_token"); // 把提取的token存入Citrus全局变量 Citrus.citrusContext().getGlobalVariables().put("global_auth_header", context.getVariable("header_token")); Citrus.citrusContext().getGlobalVariables().put("global_id_token", context.getVariable("payload_token")); } }
如果用JUnit 5,把@BeforeSuite换成@BeforeAll,并且把测试方法改成static即可。
方式2:自定义静态Token存储类
如果觉得全局变量不够直观,也可以自己写个简单的静态类来存token,更灵活:
// 自定义Token存储类,简单直接 public class TokenHolder { private static String authHeader; private static String idToken; public static void setAuthHeader(String token) { authHeader = token; } public static String getAuthHeader() { return authHeader; } public static void setIdToken(String token) { idToken = token; } public static String getIdToken() { return idToken; } }
然后在GetTokenIT里通过AbstractTestAction把token存进去:
http() .client(HttpTqaClient) .receive() .response(HttpStatus.OK) .messageType(MessageType.JSON) .extractFromHeader("Authorization", "header_token") .extractFromPayload("$.id_token", "payload_token"); action(new AbstractTestAction() { @Override public void doExecute(TestContext context) { // 从当前TestContext取出token,存入自定义存储类 TokenHolder.setAuthHeader(context.getVariable("header_token")); TokenHolder.setIdToken(context.getVariable("payload_token")); } });
三、在其他TestIT类中使用共享的Token
现在不管用哪种方式,都能在其他测试类里轻松拿到token了:
方式1:用全局变量的场景
直接用Citrus的变量占位符${variableName}(会自动从全局变量取值),或者手动从全局变量池获取:
public class UserApiTestIT extends TestNGCitrusTest { @CitrusTest public void testGetUserInfo() { // 方式A:直接用Citrus占位符,自动匹配全局变量 http() .client(HttpTqaClient) .send() .get("/api/user") .header("Authorization", "${global_auth_header}"); // 方式B:手动从全局变量池获取 String idToken = Citrus.citrusContext().getGlobalVariables().get("global_id_token"); http() .client(HttpTqaClient) .send() .post("/api/verify") .payload("{\"token\": \"" + idToken + "\"}"); } }
方式2:用自定义TokenHolder的场景
直接调用静态方法获取token,代码可读性更高:
public class OrderApiTestIT extends TestNGCitrusTest { @CitrusTest public void testCreateOrder() { http() .client(HttpTqaClient) .send() .post("/api/orders") .header("Authorization", TokenHolder.getAuthHeader()) .payload("{\"userId\": \"123\", \"token\": \"" + TokenHolder.getIdToken() + "\"}"); } }
四、注意事项
- 执行顺序:一定要确保
GetTokenIT在所有测试之前执行,TestNG的@BeforeSuite或者JUnit 5的@BeforeAll能帮你保证这一点。 - 并行测试:如果开启了并行测试,全局变量可能会有线程安全问题,这时候可以用
ThreadLocal改造TokenHolder,或者依赖Citrus的TestContext线程隔离特性。 - 变量校验:提取token后最好加个非空校验,比如
assertThat(context.getVariable("header_token")).isNotNull();,避免后续测试因为token为空失败。
内容的提问来源于stack exchange,提问作者stallewar
相关产品推荐
相关产品推荐

