| <!DOCTYPE html SYSTEM "about:legacy-compat"> |
| <html lang="en"> |
| <head> |
| <META http-equiv="Content-Type" content="text/html; charset=iso-8859-15"> |
| <title>Apache JMeter |
| - |
| User's Manual: Building a Test Plan Programmatically</title> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <link href="https://fonts.googleapis.com/css?family=Merriweather:400normal" rel="stylesheet" type="text/css"> |
| <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" rel="stylesheet" type="text/css"> |
| <link rel="stylesheet" type="text/css" href="../css/new-style.css"> |
| <link rel="apple-touch-icon-precomposed" href="../images/apple-touch-icon.png"> |
| <link rel="icon" href="../images/favicon.png"> |
| <meta name="msapplication-TileColor" content="#ffffff"> |
| <meta name="msapplication-TileImage" content="../images/mstile-144x144.png"> |
| <meta name="theme-color" content="#ffffff"> |
| </head> |
| <body role="document"> |
| <a href="#content" class="hidden">Main content</a> |
| <div class="header"> |
| <!-- |
| APACHE LOGO |
| --> |
| <div> |
| <a href="https://www.apache.org"><img title="Apache Software Foundation" class="asf-logo logo" src="../images/asf-logo.svg" alt="Logo ASF"></a> |
| </div> |
| <!-- |
| PROJECT LOGO |
| --> |
| <div> |
| <a href="https://jmeter.apache.org/"><img class="logo" src="../images/logo.svg" alt="Apache JMeter"></a> |
| </div> |
| <div class="banner"> |
| <a href="https://www.apache.org/events/current-event.html"><img src="https://www.apache.org/events/current-event-234x60.png" alt="Current Apache event teaser"></a> |
| <div class="clear"></div> |
| </div> |
| </div> |
| <div class="nav"> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">About</div> |
| <ul> |
| <li> |
| <a href="../index.html">Overview</a> |
| </li> |
| <li> |
| <a href="https://www.apache.org/licenses/">License</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">Download</div> |
| <ul> |
| <li> |
| <a href="../download_jmeter.cgi">Download Releases</a> |
| </li> |
| <li> |
| <a href="../changes.html">Release Notes</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">Documentation</div> |
| <ul> |
| <li> |
| <a href="../usermanual/get-started.html">Get Started</a> |
| </li> |
| <li> |
| <a href="../usermanual/index.html">User Manual</a> |
| </li> |
| <li> |
| <a href="../usermanual/best-practices.html">Best Practices</a> |
| </li> |
| <li> |
| <a href="../usermanual/component_reference.html">Component Reference</a> |
| </li> |
| <li> |
| <a href="../usermanual/functions.html">Functions Reference</a> |
| </li> |
| <li> |
| <a href="../usermanual/properties_reference.html">Properties Reference</a> |
| </li> |
| <li> |
| <a href="../changes_history.html">Change History</a> |
| </li> |
| <li> |
| <a href="../api/index.html">Javadocs</a> |
| </li> |
| <li> |
| <a href="https://cwiki.apache.org/confluence/display/JMETER/Home">JMeter Wiki</a> |
| </li> |
| <li> |
| <a href="https://cwiki.apache.org/confluence/display/JMETER/JMeterFAQ">FAQ (Wiki)</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">Tutorials</div> |
| <ul> |
| <li> |
| <a href="../usermanual/jmeter_distributed_testing_step_by_step.html">Distributed Testing</a> |
| </li> |
| <li> |
| <a href="../usermanual/jmeter_proxy_step_by_step.html">Recording Tests</a> |
| </li> |
| <li> |
| <a href="../usermanual/junitsampler_tutorial.html">JUnit Sampler</a> |
| </li> |
| <li> |
| <a href="../usermanual/jmeter_accesslog_sampler_step_by_step.html">Access Log Sampler</a> |
| </li> |
| <li> |
| <a href="../usermanual/jmeter_tutorial.html">Extending JMeter</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">Community</div> |
| <ul> |
| <li> |
| <a href="../issues.html">Issue Tracking</a> |
| </li> |
| <li> |
| <a href="../security.html">Security</a> |
| </li> |
| <li> |
| <a href="../mail.html">Mailing Lists</a> |
| </li> |
| <li> |
| <a href="../svnindex.html">Source Repositories</a> |
| </li> |
| <li> |
| <a href="../building.html">Building and Contributing</a> |
| </li> |
| <li> |
| <a href="https://projects.apache.org/project.html?jmeter">Project info at Apache</a> |
| </li> |
| <li> |
| <a href="https://cwiki.apache.org/confluence/display/JMETER/JMeterCommitters">Contributors</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <ul class="menu"> |
| <li onClick="return true"> |
| <div class="menu-title">Foundation</div> |
| <ul> |
| <li> |
| <a href="https://www.apache.org/">The Apache Software Foundation (ASF)</a> |
| </li> |
| <li> |
| <a href="https://www.apache.org/foundation/getinvolved.html">Get Involved in the ASF</a> |
| </li> |
| <li> |
| <a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a> |
| </li> |
| <li> |
| <a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| </li> |
| <li> |
| <a href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| <div class="main" id="content"> |
| <div class="social-media"> |
| <ul class="social-media-links"> |
| <li class="twitter"> |
| <a href="https://twitter.com/ApacheJMeter" title="Follow us on Twitter"><i class="fa fa-twitter" aria-hidden="true"></i>Twitter</a> |
| </li> |
| <li class="github"> |
| <a href="https://github.com/apache/jmeter" title="Fork us on github"><i class="fa fa-github" aria-hidden="true"></i>github</a> |
| </li> |
| </ul> |
| </div> |
| <ul class="pagelinks"> |
| <li> |
| <a href="build-jms-topic-test-plan.html">< Prev</a> |
| </li> |
| <li> |
| <a href="../index.html">Index</a> |
| </li> |
| <li> |
| <a href="listeners.html">Next ></a> |
| </li> |
| </ul> |
| <div class="section"> |
| <h1 id="building"> |
| Building a Test Plan Programmatically<a class="sectionlink" href="#building" title="Link to here">¶</a> |
| </h1> |
| |
| <div class="clear"></div> |
| <div class="note"> |
| JMeter 5.6 brings experimental classes and methods to build test plans programmatically, so please feel free to provide your feedback. |
| </div> |
| <div class="clear"></div> |
| |
| <p> |
| In this section, you will learn how to create a <a href="build-test-plan.html">Test Plan</a> with JMeter APIs. |
| </p> |
| |
| <p> |
| The Test Plan is a collection of elements arranged in a tree-like manner. However, in JMeter APIs, the elements do not form a tree. |
| Parent-child relationships are stored in a separate structure: <span class="code">ListedHashTree</span>. |
| |
| </p> |
| |
| </div> |
| <div class="section"> |
| <h1 id="low_level_api"> |
| Creating a plan with low-level APIs<a class="sectionlink" href="#low_level_api" title="Link to here">¶</a> |
| </h1> |
| |
| <p> |
| Let us create <span class="code">Test Plan => Thread Group => Debug Sampler</span> plan |
| </p> |
| |
| <p> |
| |
| <pre class="source"> |
| ListedHashTree root = new ListedHashTree(); // (1) |
| TestPlan testPlan = new TestPlan(); |
| ListedHashTree testPlanSubtree = root.add(testPlan); // (2) |
| TestPlan threadGroup = new ThreadGroup(); |
| threadGroup.setName("Search Order Thread Group"); |
| ListedHashTree threadGroupSubtree = testPlanSubtree.add(threadGroup); // (3) |
| DebugSampler debugSampler = new DebugSampler(); |
| threadGroupSubtree.add(debugSampler);</pre> |
| |
| <ul> |
| |
| <li> |
| Firstly, we create the tree at <span class="code">(1)</span> |
| </li> |
| |
| <li> |
| Then we create elements, and add them to the tree in <span class="code">(2)</span> |
| </li> |
| |
| <li> |
| Note how adding element returns the subtree, so we add <span class="code">threadGroup</span> under <span class="code">testPlan</span> in <span class="code">(2)</span> |
| </li> |
| |
| </ul> |
| |
| <div class="clear"></div> |
| <div class="note"> |
| Don't confuse <span class="code">ListedHashTree</span> with <span class="code">HashTree</span>. <span class="code">HashTree</span> does not honour element order, so the generated elements might shuffle unexpectedly. |
| |
| </div> |
| <div class="clear"></div> |
| |
| </p> |
| |
| </div> |
| <div class="section"> |
| <h1 id="generating_code"> |
| Generating code from UI<a class="sectionlink" href="#generating_code" title="Link to here">¶</a> |
| </h1> |
| |
| <p> |
| To aid with creating code, JMeter implements <span class="code">Copy Code</span> context action, so you could |
| generate code for any element in the plan. It would generate code for the element and its children. |
| </p> |
| |
| <figure> |
| <a href="../images/screenshots/copy_code/http_sampler_copy_code.png"><img src="../images/screenshots/copy_code/http_sampler_copy_code.png" width="380" height="258" alt="Copy Code context action"></a> |
| <figcaption>Copy Code context action</figcaption> |
| </figure> |
| |
| <p> |
| Here's the generated code (Kotlin DSL): |
| |
| <pre class="source"> |
| org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy::class { |
| props { |
| it[arguments] = org.apache.jmeter.config.Arguments().apply { |
| props { |
| it[arguments] = listOf( |
| org.apache.jmeter.protocol.http.util.HTTPArgument().apply { |
| props { |
| it[value] = "World" |
| it[metadata] = "=" |
| it[useEquals] = true |
| it[argumentName] = "user" |
| } |
| }, |
| org.apache.jmeter.protocol.http.util.HTTPArgument().apply { |
| props { |
| it[alwaysEncode] = true |
| it[value] = "test_value" |
| it[metadata] = "=" |
| it[useEquals] = true |
| it[argumentName] = "test" |
| } |
| }, |
| ) |
| it[name] = "User Defined Variables" |
| it[guiClass] = "org.apache.jmeter.protocol.http.gui.HTTPArgumentsPanel" |
| it[testClass] = "org.apache.jmeter.config.Arguments" |
| } |
| } |
| it[domain] = "example.com" |
| it[path] = "/api/v1/login" |
| it[method] = "GET" |
| it[followRedirects] = true |
| it[useKeepalive] = true |
| it[proxy.scheme] = "https" |
| it[proxy.host] = "localhost" |
| it[proxy.port] = "8080" |
| it[proxy.username] = "secret" |
| it[proxy.password] = "password1" |
| it[name] = "/login" |
| it[guiClass] = "org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui" |
| } |
| |
| org.apache.jmeter.extractor.RegexExtractor::class { |
| props { |
| it[guiClass] = "org.apache.jmeter.extractor.gui.RegexExtractorGui" |
| it[name] = "extract user id" |
| it[referenceName] = "regexVar" |
| it[regularExpression] = "hello\\s+?world" |
| it[template] = "\$1\$" |
| } |
| } |
| |
| org.apache.jmeter.protocol.http.control.HeaderManager::class { |
| props { |
| it[headers] = listOf( |
| org.apache.jmeter.protocol.http.control.Header().apply { |
| props { |
| it[headerName] = "Accept" |
| it[value] = "text/plain" |
| } |
| }, |
| org.apache.jmeter.protocol.http.control.Header().apply { |
| props { |
| it[headerName] = "User-Agent" |
| it[value] = "JMeter" |
| } |
| }, |
| org.apache.jmeter.protocol.http.control.Header().apply { |
| props { |
| it[headerName] = "X-JMeter-Thread" |
| it[value] = "Thread \${__threadNum}" |
| } |
| }, |
| ) |
| it[guiClass] = "org.apache.jmeter.protocol.http.gui.HeaderPanel" |
| it[name] = "HTTP Header Manager" |
| } |
| } |
| } |
| </pre> |
| |
| </p> |
| |
| </div> |
| <div class="section"> |
| <h1 id="treebuilder_kotlin_dsl"> |
| Creating a plan with Kotlin DSL<a class="sectionlink" href="#treebuilder_kotlin_dsl" title="Link to here">¶</a> |
| </h1> |
| |
| <p>JMeter 5.6 introduces Kotlin DSL which might make it easier to create and maintain test plans as the structure of the code |
| would resemble the structure of the generated test plan tree</p> |
| |
| <p> |
| |
| <pre class="source"> |
| import org.apache.jmeter.sampler.DebugSampler |
| import org.apache.jmeter.testelement.TestPlan |
| import org.apache.jmeter.threads.ThreadGroup |
| import org.apache.jmeter.treebuilder.dsl.testTree |
| |
| val root = testTree { // (1) |
| TestPlan::class { // (2) |
| ThreadGroup::class { |
| name = "Search Order Thread Group" |
| +DebugSampler::class // (3) |
| +DebugSampler() // (4) |
| } |
| } |
| }</pre> |
| |
| <ul> |
| |
| <li> |
| Firstly, we create a <span class="code">TreeBuilder</span> at <span class="code">(1)</span> |
| </li> |
| |
| <li> |
| Then we add elements to the tree in <span class="code">(2)</span>, and populate its children |
| </li> |
| |
| <li> |
| Note how adding element returns the subtree, so we add <span class="code">threadGroup</span> under <span class="code">testPlan</span> in <span class="code">(2)</span> |
| </li> |
| |
| <li> |
| If no children needed, the element can be appended to the tree with a unary plus operator as in <span class="code">(3)</span> |
| </li> |
| |
| <li> |
| By default, JMeter uses no-argument constructors to create elements, however, you can add <span class="code">TestElement</span> instances to the tree as well, see <span class="code">(4)</span> |
| </li> |
| |
| </ul> |
| |
| </p> |
| |
| </div> |
| <div class="section"> |
| <h1 id="extending_treebuilder_kotlin_dsl"> |
| Extending Kotlin DSL<a class="sectionlink" href="#extending_treebuilder_kotlin_dsl" title="Link to here">¶</a> |
| </h1> |
| |
| <p> |
| As you use the DSL for test plan generation, you might want to factor out the common patterns. |
| For instance, imagine you want factor out <span class="code">Thread Group</span> creation so it always has a <span class="code">Summariser</span> element. |
| </p> |
| |
| <p> |
| |
| <pre class="source"> |
| import kotlin.time.Duration.Companion.seconds |
| import org.apache.jmeter.sampler.DebugSampler |
| import org.apache.jmeter.testelement.TestPlan |
| import org.apache.jmeter.threads.ThreadGroup |
| import org.apache.jmeter.treebuilder.dsl.testTree |
| |
| fun TreeBuilder.threadGroup( // (1) |
| name: String, |
| numThreads: Int = 10, |
| rampUp: Duration = 3.seconds, |
| body: Action<ThreadGroup> |
| ) { |
| ThreadGroup::class { // (2) |
| this.name = name |
| this.numThreads = numThreads |
| this.rampUp = rampUp.inWholeSeconds.toInt() |
| +Summariser::class |
| body(this) // (3) |
| } |
| } |
| |
| fun buildTree() { |
| val root = testTree { |
| TestPlan::class { |
| threadGroup(name = "Search Order Thread Group", rampUp = 1.seconds) { // (4) |
| +DebugSampler::class |
| } |
| } |
| }</pre> |
| |
| <ul> |
| |
| <li> |
| Firstly, you can factor test element creation logic as an extension function for <span class="code">TreeBuilder</span> as in <span class="code">(1)</span>. |
| It uses regular DSL to add an element (see <span class="code">(2)</span>), and then it calls the lambda body in <span class="code">(3)</span> to fill thread group children. |
| </li> |
| |
| <li> |
| You can use the extension by calling it when you need it in the test plan, see <span class="code">(4)</span> |
| </li> |
| |
| <li>Note how named parameters, and default values keep the code readable</li> |
| |
| </ul> |
| |
| </p> |
| |
| </div> |
| <div class="section"> |
| <h1 id="treebuilder_java_dsl"> |
| Creating a plan with Java DSL<a class="sectionlink" href="#treebuilder_java_dsl" title="Link to here">¶</a> |
| </h1> |
| |
| <p>JMeter 5.6 introduces Java DSL which might make it easier to create and maintain test plans as the structure of the code |
| would resemble the structure of the generated test plan tree</p> |
| |
| <p> |
| |
| <pre class="source"> |
| import org.apache.jmeter.sampler.DebugSampler |
| import org.apache.jmeter.testelement.TestPlan |
| import org.apache.jmeter.threads.ThreadGroup |
| import static org.apache.jmeter.treebuilder.dsl.TreeBuilders.testTree |
| |
| ListedHashTree root = testTree(b -> { // (1) |
| b.add(TestPlan.class, tp -> { // (2) |
| b.add(ThreadGroup.class, tg -> { |
| tg.setName("Search Order Thread Group"); |
| b.add(DebugSampler.class); // (3) |
| b.add(new DebugSampler()); // (4) |
| }); |
| }); |
| });</pre> |
| |
| <ul> |
| |
| <li> |
| Firstly, we create a <span class="code">TreeBuilder</span> at <span class="code">(1)</span>. |
| Note how this builder reference should be used to append all the elements |
| </li> |
| |
| <li> |
| Then we add elements to the tree in <span class="code">(2)</span>, and populate its children. |
| The lambda parameters correspond to the added elements, so you can configure their properties |
| </li> |
| |
| <li> |
| Note how adding element returns the subtree, so we add <span class="code">threadGroup</span> under <span class="code">testPlan</span> in <span class="code">(2)</span> |
| </li> |
| |
| <li> |
| If no children needed, you could omit the lambda parameter as in <span class="code">(3)</span> |
| </li> |
| |
| <li> |
| By default, JMeter uses no-argument constructors to create elements, however, you can add <span class="code">TestElement</span> instances to the tree as well, see <span class="code">(4)</span> |
| </li> |
| |
| </ul> |
| |
| </p> |
| |
| </div> |
| <ul class="pagelinks"> |
| <li> |
| <a href="build-jms-topic-test-plan.html">< Prev</a> |
| </li> |
| <li> |
| <a href="../index.html">Index</a> |
| </li> |
| <li> |
| <a href="listeners.html">Next ></a> |
| </li> |
| </ul> |
| <div class="share-links"> |
| Share this page: |
| |
| <ul> |
| <li class="fb"> |
| <a data-social-url="https://facebook.com/sharer/sharer.php?u=" title="Share on facebook"><i class="fa fa-facebook" aria-hidden="true"></i>share</a> |
| </li> |
| <li class="twitter"> |
| <a data-social-url="https://twitter.com/intent/tweet?url=" title="Tweet on twitter"><i class="fa fa-twitter" aria-hidden="true"></i>tweet</a> |
| </li> |
| </ul> |
| </div> |
| <a href="#top" id="topButton">Go to top</a> |
| </div> |
| <div class="footer"> |
| <div class="copyright"> |
| Copyright © |
| 1999 – |
| 2024 |
| , Apache Software Foundation |
| </div> |
| <div class="trademarks">Apache, Apache JMeter, JMeter, the Apache |
| feather, and the Apache JMeter logo are |
| trademarks of the |
| Apache Software Foundation. |
| </div> |
| </div> |
| <script>(function(){ |
| "use strict"; |
| // enable 'go to top' button functionality |
| document.addEventListener('scroll', function() { |
| if (document.body.scrollTop > 500 || document.documentElement.scrollTop > 500) { |
| document.getElementById("topButton").style.display = "block"; |
| } else { |
| document.getElementById("topButton").style.display = "none"; |
| } |
| }); |
| // fill in the current location into social links on this page. |
| var as = document.getElementsByTagName('a'); |
| var loc = document.location.href; |
| if (!loc.toLowerCase().startsWith('http')) { |
| return; |
| } |
| for (var i=0; i<as.length; i++) { |
| var href = as[i].getAttribute('data-social-url'); |
| if (href !== null) { |
| as[i].href = href + encodeURIComponent(loc); |
| } |
| } |
| })();</script> |
| </body> |
| </html> |