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

JSR223 PostProcessor在tearDown线程组中无法正常工作

JMeter props清理失效问题排查与解决

我创建了一个测试计划,流程如下:

  • 添加Setup线程组,通过多个HTTP请求及对应JSR223断言验证前置条件
  • 断言失败时,将采样器名称和预期值存入以failedSampler_开头的props属性中,用于后续普通线程组针对缺失数据执行操作

Setup线程组中JSR223断言代码(Groovy):

import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.assertions.AssertionResult;

// JSR223 Assertion (Groovy)
String expectedValue = "test"; // 替换为你的预期值
String jsonString = prev.getResponseDataAsString();


def jsonSlurper = new groovy.json.JsonSlurper()
def jsonObject = jsonSlurper.parseText(jsonString)
log.info(jsonObject.toString());

boolean matchFound = false;

// 遍历hits数组,从每个文档中获取_name字段值
jsonObject.data.record.hits.each { hit ->
    String actualValue = hit._name;
    log.info("实际值为: " + actualValue);

    if (expectedValue.equals(actualValue)) {
        matchFound = true;
    }
}

if (!matchFound) {
    String sampleName = SampleResult.getSampleLabel();
    String failureMessage = "采样器断言失败: " + sampleName +
        "\n预期值: " + expectedValue +
        "\n未找到匹配的实际值";
    props.put("failedSampler_" + sampleName, expectedValue);
    log.error(failureMessage);

    // 创建断言结果
    AssertionResult result = new AssertionResult("${expectedValue} 未找到");
    result.setFailure(true);
    result.setFailureMessage(failureMessage);
    prev.addAssertionResult(result);
    prev.setSuccessful(false);
}

为验证清理逻辑,我在TearDown线程组中配置了JSR223后置处理器清除props数据,但该处理器无法彻底清除props,下一次运行时仍保留上一次的数据。TearDown中的代码如下:

import org.apache.jmeter.reporters.ResultCollector
import org.apache.jorphan.collections.SearchByClass


def engine = ctx.getEngine()
def test = engine.getClass().getDeclaredField('test')

test.setAccessible(true)

def testPlanTree = test.get(engine)

SearchByClass<ResultCollector> listenerSearch = new SearchByClass<>(ResultCollector.class)
testPlanTree.traverse(listenerSearch)
Collection<ResultCollector> listeners = listenerSearch.getSearchResults()

listeners.each { listener ->
    def files = listener.files
    files.each { file ->
        file.value.pw.close()
    }
}

log.info('清理前props大小:' +props.size()) 
props.clear()
log.info('清理后props大小:' +props.size()) 

注:当前Setup与TearDown线程组之间未添加普通线程组,核心需求是将断言失败的预期值与采样器名称关联存储到props,供后续普通线程组访问并处理缺失数据。


问题原因分析

  1. props的生命周期:JMeter的props是JVM级别的全局属性,除非JVM进程重启,否则默认不会自动彻底清除。props.clear()仅清除当前测试运行的内存数据,但如果JMeter进程持续运行,下一次测试会复用JVM环境,残留之前的props数据。
  2. TearDown执行限制:TearDown线程组在测试计划末尾执行,props.clear()执行后,若JMeter进程未关闭,props仍会驻留在JVM内存中,下一次测试运行时会被读取。

解决方案

方案1:测试启动前清除指定前缀的props

在Setup线程组的最开头添加一个JSR223 Sampler,专门清理上一次遗留的failedSampler_开头的props:

// 清除所有以failedSampler_开头的props属性
def keysToRemove = props.keySet().findAll { it.startsWith('failedSampler_') }
keysToRemove.each { props.remove(it) }
log.info("已清除上一次遗留的${keysToRemove.size()}个failedSampler属性")

方案2:标记临时属性精准清理

在断言存储时为props添加临时标记,TearDown阶段仅清理标记过的属性:

  • 断言代码中存储逻辑修改:
props.put("failedSampler_" + sampleName, expectedValue)
// 添加临时属性标记
props.put("temp_" + sampleName, "true")
  • TearDown中的清理代码修改:
def tempKeys = props.keySet().findAll { it.startsWith('temp_') }
tempKeys.each { 
    String originalKey = "failedSampler_" + it.replace('temp_', '')
    props.remove(originalKey)
    props.remove(it)
}
log.info("已清除${tempKeys.size()}个临时props属性")

方案3:CI/CD场景强制重启进程

在自动化测试流水线中,每次测试运行后关闭JMeter进程,避免JVM复用导致的props残留,从根源上解决数据污染问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:03:29