jmeter 核心_Java 代码调用 Jmeter

一、Jmeter的简介
Jmeter一款开源的压力测试工具,而这款开源的测试工具是基于Java开发。Jmeter最初的设计是为了web的性能测试。而在后面扩展了很多种类的测试。
Jmeter是基于Java编写,所以使用时需要安装jdk
二、Jmeter负载测试和性能测试种类
1.Web - HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET, …)
2.SOAP / REST Webservices
3.FTP
4.Database via JDBC
5.LDAP
6.Message-oriented middleware (MOM) via JMS
7.Mail - SMTP(S), POP3(S) and IMAP(S)
8.Native commands or shell scripts
9.TCP
10.Java Objects
三、Jmeter基本组件简介
我们这里只讲解使用到的一些组件。而其他组件可以到Jmeter的官网了解(https://jmeter.apache.org/),在Jmeter下每个组件都是节点的方式进行配置。如我们在图形化界面中,都会有一个TestPlan的根节点,其他控件都添加在根节点下。
3.1.TestPlan
测试计划,每一个测试都为一个测试计划。
2.ThreadGroup:是一个测试计划的开始。所有的controller、sampler必须在线程组下。不过有一些特许的控件如Listeners可以直接在TestPlan下。
3.sampler:采样器,也就是我们各种性能测试和负载测试的收集器。如:http采样器:HTTPSampler等
4.Controller:主要用于压力测试逻辑的处理,如我们这里使用了LoopController进行控制线程的循环次数,是永久还是循环压力测试多次。
四、Jmeter的调用方式
调用Jmeter有5中方式:

  • 使用命令的方式
  • 使用ANT的方式
  • 使用MAVEN的PLUGIN方式
  • 使用JAVA代码调用
  • 使用blazemeter进行调用
    这里只演示JAVA调用,其他方式的调用可以blazemeter的文章(https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui)

五、使用JAVA调用jmeter
一、创建项目
我们这里使用了Ecplise IDE创建Maven项目。
二、导入Jmeter的包

 我们这里演示使用的是http的压力测试。所以会用到ApacheJMeter_http的包和ApacheJMeter_core的包
  <!--jmeter核心包-->
       <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_core</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter组件包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_components</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter Http包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_http</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

三、演示代码

package com.study;

import java.io.File;

import org.apache.jmeter.JMeter;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;

public class TestPlanLauncher {

    public static void main(String[] args) {
        // jemter 引擎
        StandardJMeterEngine standardJMeterEngine = new StandardJMeterEngine();
        // 设置不适用gui的方式调用jmeter
        System.setProperty(JMeter.JMETER_NON_GUI, "true");
        // 设置jmeter.properties文件,我们将jmeter文件存放在resources中,通过classload
        String path = TestPlanLauncher.class.getClassLoader().getResource("jmeter.properties").getPath();
        File jmeterPropertiesFile = new File(path);
        if (jmeterPropertiesFile.exists()) {
            JMeterUtils.loadJMeterProperties(jmeterPropertiesFile.getPath());
            HashTree testPlanTree = new HashTree();
            // 创建测试计划
            TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
            // 创建http请求收集器
            HTTPSamplerProxy examplecomSampler = createHTTPSamplerProxy();
            // 创建循环控制器
            LoopController loopController = createLoopController();
            // 创建线程组
            ThreadGroup threadGroup = createThreadGroup();
            // 线程组设置循环控制
            threadGroup.setSamplerController(loopController);
            // 将测试计划添加到测试配置树种
            HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
            // 将http请求采样器添加到线程组下
            threadGroupHashTree.add(examplecomSampler);
            //增加结果收集
            Summariser summer = null;
            String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
            if (summariserName.length() > 0) {
                summer = new Summariser(summariserName);
            }
            ResultCollector logger = new ResultCollector(summer);
            testPlanTree.add(testPlanTree.getArray(), logger);
            
            // 配置jmeter
            standardJMeterEngine.configure(testPlanTree);
            // 运行
            standardJMeterEngine.run();
        }
    }

    /**
     * 创建线程组
     * 
     * @return
     */
    public static ThreadGroup createThreadGroup() {
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Example Thread Group");
        threadGroup.setNumThreads(1);
        threadGroup.setRampUp(0);
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
        threadGroup.setScheduler(true);
        threadGroup.setDuration(60);
        threadGroup.setDelay(0);
        return threadGroup;
    }

    /**
     * 创建循环控制器
     * 
     * @return
     */
    public static LoopController createLoopController() {
        // Loop Controller
        LoopController loopController = new LoopController();
        loopController.setLoops(-1);
        loopController.setContinueForever(true);
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
        loopController.initialize();
        return loopController;
    }

    /**
     * 创建http采样器
     * 
     * @return
     */
    public static HTTPSamplerProxy createHTTPSamplerProxy() {
        HeaderManager headerManager = new HeaderManager();
        headerManager.setProperty("Content-Type", "multipart/form-data");
        HTTPSamplerProxy httpSamplerProxy = new HTTPSamplerProxy();
        httpSamplerProxy.setDomain("www.baidu.com");
        httpSamplerProxy.setPort(80);
        httpSamplerProxy.setPath("/");
        httpSamplerProxy.setMethod("GET");
        httpSamplerProxy.setConnectTimeout("5000");
        httpSamplerProxy.setUseKeepAlive(true);
        httpSamplerProxy.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
        httpSamplerProxy.setHeaderManager(headerManager);
        return httpSamplerProxy;
    }
}

三、详讲
3.1 Jmeter引擎StandardJMeterEngine
StandardJMeterEngine是Java调用Jmeter的入口。
3.2 Jmeter.properties文件

  • 指定Jmeter.properties文件,Jmeter.properties文件主要用于Jmeter全局基础配置。我们可以根据自己的需求进行修改配置文件。
    例如我们需要进行分布式压力测试的情况下,我们就需要在remote_hosts添加远程的IP。
  • 指定jmeter.properties文件的方式,我们可以通过源码的分析发现加载配置Jmeter.properties配置文件,先从指定的文件中查找,如果查找不到jmeter.properties文件,会在org/apache/jmeter/jmeter.properties查找查找。也就是说我们可以将配置文件存放在org/apache/jmeter路径下或者指定配置文件。
    public static void loadJMeterProperties(String file) {
        Properties p = new Properties(System.getProperties());
        InputStream is = null;
        try {
            File f = new File(file);
            is = new FileInputStream(f);
            p.load(is);
        } catch (IOException e) {
            try {
                is = ClassLoader.getSystemResourceAsStream(
                        "org/apache/jmeter/jmeter.properties"); // $NON-NLS-1$
                if (is == null) {
                    throw new RuntimeException("Could not read JMeter properties file:" + file);
                }
                p.load(is);
            } catch (IOException ex) {
                throw new RuntimeException("Could not read JMeter properties file:" + file);
            }
        } finally {
            JOrphanUtils.closeQuietly(is);
        }
        appProperties = p;
    }

3.3 HashTree
我们在使用Jmeter的图形化界面的时候,我们可以看出所有组件都是添加在TestPlan下。而在使用非图形化界面的时,我们的StandardJMeterEngine通过configure方法来进行配置我们的TestPlan、ThreadGroup、LoopController等组件,因此需要创建HashTree。
3.4 TestPlan
我们在使用图形化界面都知道所有组件都是存放在TestPlan中,所以我们需要创建一个TestPlan用于存放组件。
3.5 HTTPSamplerProxy
HTTPSamplerProxy是HTTP采样器,在Jmeter中提供做了多种采样器,我们可以根据采样数据来确定到底使用哪一个采样器。在压力测试时,是通过Thread Group来进行创建线程进行压力测试的。每个线程都需要通过Sampler来确定去并发访问,因此Sampler是存放在Thread Group下。

5913315369e5e318ad1b83243ecd5782.png

3.6 LoopController
LoopController是一个压力循环次数的控制器。我们通常会配置ThreadGroup进行使用,例如我们在Thread Group中设置持续5秒,并发量50的情况下,我们会这是LoopController为永久循环。我们需要注意:永久循环的情况下loops应设置为-1.

 loopController.setLoops(-1);
 loopController.setContinueForever(true);
注意:Controller是存放在Thread Group下。

3.7 ThreadGroup
在Jmeter下是通过线程方式去并发访问,线程管理Jmeter通过ThreadGroup来控制线程的数量和线程的创建、线程持续访问的时间。
3.8 ResultCollector

  • ResultCollector是一个结果的收集器,ResultController收集请求结果是通过监听的方式进行收集结果。
  • 通过查看ResultController的源码发现其实现了SampleListener接口,并且调用sampleOccurred方法处理每个sampler的结果。
    /**
     * When a test result is received, display it and save it.
     *
     * @param event
     *            the sample event that was received
     */
    @Override
    public void sampleOccurred(SampleEvent event) {
        SampleResult result = event.getResult();

        if (isSampleWanted(result.isSuccessful())) {
            sendToVisualizer(result);
            if (out != null && !isResultMarked(result) && !this.isStats) {
                SampleSaveConfiguration config = getSaveConfig();
                result.setSaveConfig(config);
                try {
                    if (config.saveAsXml()) {
                        SaveService.saveSampleResult(event, out);
                    } else { // !saveAsXml
                        String savee = CSVSaveService.resultToDelimitedString(event);
                        out.println(savee);
                    }
                } catch (Exception err) {
                    log.error("Error trying to record a sample", err); // should throw exception back to caller
                }
            }
        }

        if(summariser != null) {
            summariser.sampleOccurred(event);
        }
    }

在ResultController.sampleOccurred方法中我们可以看到summariser不为空的情况下调用summariser的sampleOccurred方法,从summariser.sampleOccurred方法我们可以知道summariser一定是实现了SampleListener接口。

public class Summariser extends AbstractTestElement
    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {

在多线程的情况下,Jmeter会对Controller、Sampler等组件为每个线程拷贝一份对象。而对于组件ResultCollector是不拷贝对象。

/**
 * This class handles all saving of samples.
 * The class must be thread-safe because it is shared between threads (NoThreadClone).
 */
public class ResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
        TestStateListener, Remoteable, NoThreadClone {

Reference:
https://jmeter.apache.org/api/index.html
https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui
https://jmeter.apache.org/usermanual/get-started.html

当使用 JMeter 进行压测时,可以使用 Java 代码片段来实现复杂的测试逻辑。下面是一个示例的 Java 代码片段,用于在 JMeter 进行压测: ```java import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient; import org.apache.jmeter.samplers.SampleResult; public class MySampler implements JavaSamplerClient { // 初始化方法,可在此处进行一些初始化操作 @Override public void setupTest(JavaSamplerContext context) { // 初始化操作 } // 设置线程数 @Override public Arguments getDefaultParameters() { Arguments arguments = new Arguments(); arguments.addArgument("ThreadCount", "10"); return arguments; } // 执行压测逻辑的方法 @Override public SampleResult runTest(JavaSamplerContext context) { SampleResult result = new SampleResult(); boolean success = true; result.sampleStart(); // 记录测试开始时间 try { // 执行压测逻辑,可以调用其他类或方法 // ... } catch (Exception e) { success = false; result.setResponseMessage("Exception: " + e); result.setSuccessful(false); } finally { result.sampleEnd(); // 记录测试结束时间 // 设置测试结果 if (success) { result.setResponseMessage("Test successful"); result.setSuccessful(true); } } return result; } // 结束方法,可在此处进行一些清理操作 @Override public void teardownTest(JavaSamplerContext context) { // 清理操作 } } ``` 在 JMeter ,可以使用 BeanShell Sampler 或 JSR223 Sampler 来调用上述 Java 代码片段。需要将代码片段编译为 JAR 文件,并将其放置在 JMeter 的 lib/ext 目录下。然后,在 JMeter 创建一个 BeanShell Sampler 或 JSR223 Sampler,调用 MySampler 类的方法。 以上仅是一个示例,具体的压测逻辑和参数设置可根据实际需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值