1.背景

2.目的

3.实战

   脚本结构(全部交易默认成功):

  脚本中sampler都用相同代码来模拟,可以通过random参数控制返回内容,sleep参数控制交易耗时。

public class JMeterTransaction extends AbstractJavaSamplerClient {
​
    @Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        arguments.addArgument("random","1");
        arguments.addArgument("sleep","50");
        return arguments;
    }
​
    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        SampleResult result = new SampleResult();
        result.sampleStart();
        String random = arg0.getParameter("random");
        long sleep = Long.valueOf(arg0.getParameter("sleep"));
        try {
            TimeUnit.MILLISECONDS.sleep(sleep);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.setSuccessful(true);
        result.setResponseCodeOK();
        result.setResponseData(random,"UTF-8");
        result.sampleEnd();
        return result;
    }
}

10并发执行1min结果:

嗯?各接口样本数为什么不一样?有点意思?理论上每个接口样本数应该一致啊。。。。。

宝路调整了下事务控制器配置,勾选了Genernate parent sampler

10并发执行1min结果:

感觉目前没啥问题,宝路将执行过程中的结果保存了,打开本次jtl结果:

嗯?如出一辙。。。从目前看与事务原子性,登录成功多少笔,其余的交易就应该成功多少笔。目前能看JMeter的事务控制不符合原子性,难道是我使用的姿势有问题?

    多次执行过,宝路发现个共性:同一个测试计划的各接口的样本总数是递减的。所以宝路做了推测:在场景停止时(线程数从某个设定的值下降到0),比如某个线程在执行完“查询卡列表”时,线程就被kill了,进而导致“查询余额”接口没被执行。

宝路又做了验证:

不勾选事务控制器Genernate parent sampler

勾选事务控制器Genernate parent sampler

清除结果后,使用聚合报告打开本次执行的jtl结果:

经过多次执行,发了个诡异现象:在不勾选Genernate parent sampler时,事务控制器统计的样本数与最后一个接口统计的样本数相同,在勾选Genernate parent sampler时,事务控制器统计的样本数与首个接口统计的样本数相同。

先不管这个是不是BUG,从事务角度看不满足原子性。单纯的事务控制器并不严格的具备原子性,这是目前看到的表像。

那么怎么解决呢?宝路之前写过一篇关于JavaRequest探究的文章,感兴趣的同学可以点击看下。本文就不过多阐述了。直接看结果

清除聚合报告数据后,再打开本次执行的jtl结果文件

嗯,真香。目前觉得唯一的缺点就是没有一个能监听subResult的插件。相同的场景,都是基于java请求的编写的底层脚本,唯一的区别就是组织方式不同。

其实你完全可以这样看:把TestJavaLee中的main看成事务控制器,你细细品,再细细品。。。。

进而宝路得出:单纯用事务控制器来组织多个sampler,严格来说不具有事务的原子性。

如果有不同想法或者看法,欢迎给宝路留言,最后附下TestJavaLee代码:

public class TestJavaLee extends AbstractJavaSamplerClient {
    @Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        arguments.addArgument("subResult","RAW_NO");
        return arguments;
    }
​
    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        SampleResult main = new SampleResult();
        main.setSampleLabel("Main事务");
        main.sampleStart();
​
        SampleResult sample_a = new SampleResult();
        sample_a.setSampleLabel("登录");
        sample_a.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_a.sampleEnd();
        sample_a.setSuccessful(true);
        main.addSubResult(sample_a,false);
​
        SampleResult sample_b = new SampleResult();
        sample_b.setSampleLabel("活动信息");
        sample_b.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(70);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_b.sampleEnd();
        sample_b.setSuccessful(true);
        main.addSubResult(sample_b,false);
​
        SampleResult sample_c = new SampleResult();
        sample_c.setSampleLabel("查卡列表");
        sample_c.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(80);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_c.sampleEnd();
        sample_c.setSuccessful(true);
​
        main.addSubResult(sample_c,false);
​
        SampleResult sample_d = new SampleResult();
        sample_d.setSampleLabel("查询余额");
        sample_d.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_d.sampleEnd();
        sample_d.setSuccessful(true);
​
        main.addSubResult(sample_d,false);
​
        main.setSuccessful(true);
        return main;
    }
​
}
12-17 14:29