You need to enable JavaScript to run this app. TestNG测试类是否需通过构造函数初始化辅助类对象与实例变量?
优惠活动
大模型
产品
解决方案
定价
更多

TestNG测试类是否需通过构造函数初始化辅助类对象与实例变量?

问题结论

你当前在类成员声明处直接初始化的写法不是TestNG测试场景下的最佳实践,更推荐你将测试相关的初始化逻辑放到@BeforeClass(类级别通用资源)和@BeforeMethod(单测试用例独立资源)中,而非构造函数或者声明处直接初始化。

核心原因说明
  • TestNG有严格的生命周期执行顺序,成员声明处的初始化逻辑会早于父类TestBase的所有TestNG钩子(比如父类的@BeforeSuite/@BeforeClass初始化逻辑)执行,如果你的辅助类构造、Partner.get()等逻辑依赖父类中初始化的配置(比如测试环境地址、全局鉴权信息),直接声明初始化会出现依赖缺失、空指针等问题,排查难度很高。
  • 构造函数的执行时机同样早于TestNG的所有注解钩子,而且无法兼容TestNG的参数注入能力(比如从testng.xml传入的环境参数、@Parameters注解的动态值),仅适合完全无依赖的基础对象初始化,绝大多数测试业务场景都不适用。
  • @BeforeClass是TestNG官方推荐的类级别资源初始化位置,执行时机在所有父类前置逻辑、测试套件级别的前置逻辑执行完成之后,能保证所有依赖的配置都已加载完成,而且可以直接使用TestNG的参数注入、依赖注入能力,初始化报错时的日志也更清晰,方便定位问题。
针对你的代码的优化建议

你当前的代码还有一个隐藏问题:两个测试方法共用同一个requestId,如果你的接口要求请求ID唯一,第二个测试用例会直接触发幂等校验报错,所以requestId应该放到@BeforeMethod中初始化,保证每个测试用例拿到独立的ID。

优化后的代码示例:

public class GetPaymentDetailsTests extends TestBase {
    String authToken;
    String partnerId;
    String requestId;
    MerchantAdapterHelper merchantAdapterHelper;
    CustomerAdapterHelper customerAdapterHelper;
    GopayAPIsHelper gopayAPIsHelper;
    public static final String redirectURL = "https://www.google.com";

    @BeforeClass(alwaysRun = true)
    public void initClassLevelResources() {
        authToken = Partner.get(WithScope.CHECKOUT_USER_GROUP).getBasicToken();
        partnerId = Partner.get(WithScope.CHECKOUT_USER_GROUP).getPartnerId();
        // 无状态的辅助类统一在类级别初始化即可
        merchantAdapterHelper = new MerchantAdapterHelper();
        customerAdapterHelper = new CustomerAdapterHelper();
        gopayAPIsHelper = new GopayAPIsHelper();
    }

    @BeforeMethod(alwaysRun = true)
    public void initMethodLevelResources() {
        // 每个测试方法生成独立的请求ID,避免用例之间互相干扰
        requestId = UUID.randomUUID().toString();
    }

    @Test(groups = {Categories.SMOKE_PAYMENT_EXPERIENCE, Categories.REGRESSION_PAYMENT_EXPERIENCE, Categories.CHECKOUT, Categories.GOPAY_APIS, Categories.PAYMENT_EXPERIENCE, Countries.ID})
    public void validateGetPaymentDetailsAPIByReferenceID(){
        Customer customer = customerHelper.getCustomer(CustomerGroup.P2M_ONLINE);

        CollectResponse collectPaymentResponse = merchantAdapterHelper.linkWalletAndInitiateCollectPaymentRequest(authToken, requestId, partnerId, OnlineMerchants.JD_ID.getMerchantID(), customer, 2, redirectURL, "en_EN" );
        String referenceID = merchantAdapterHelper.getParamValueFromnextActionURL(collectPaymentResponse.getData().getNext_action().getRedirect_to_url(), "reference");

        Assert.assertEquals(gopayAPIsHelper.getPaymentDetailsByReferenceID(referenceID).getHttpStatusCode(), HttpStatus.SC_OK, "Failed to get Get Payment Details response");
    }

    @Test(groups = {Categories.SMOKE_PAYMENT_EXPERIENCE, Categories.REGRESSION_PAYMENT_EXPERIENCE, Categories.CHECKOUT, Categories.GOPAY_APIS, Categories.PAYMENT_EXPERIENCE, Countries.ID})
    public void validateGetPaymentDetailsAPIResponseByStateID(){
        Customer customer = customerHelper.getCustomer(CustomerGroup.P2M_ONLINE);

        CollectResponse collectPaymentResponse = merchantAdapterHelper.linkWalletAndInitiateCollectPaymentRequest(authToken, requestId, partnerId, OnlineMerchants.TEST_USER_SOURABH.getMerchantID(), customer, 2, redirectURL, "en_EN" );
        String stateID = merchantAdapterHelper.getParamValueFromnextActionURL(collectPaymentResponse.getData().getNext_action().getRedirect_to_url(), "id");

        Assert.assertEquals(gopayAPIsHelper.getPaymentDetailsByStateID(stateID).getHttpStatusCode(), HttpStatus.SC_OK, "Failed to get Get Payment Details response");
    }
}
额外优化点

如果你的几个Helper类都是无状态的工具类,也可以直接提取到父类TestBase中统一初始化,所有子类直接复用即可,不需要每个测试类都重复实例化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 19:15:03