Getting Started with JMeter DSL
Tags: performance, java, testing, tutorial
Published: 2022-05-02 18:45:10

<!-- wp:paragraph -->
<p>Apache JMeter used to be a developer tool. It was primarily created to test Apache JServ (replaced by TomCat project) by Stefano Mazzocchi. After several enhancements were made to the GUI, JMeter has become a tester-friendly tool. Modern developers use Gatling or k6 or Locust as their go-to performance testing tool to quickly test their services. Now the time has come to JMeter to gain more developers' attention via DSL.  In this blog article, we are going to see about JMeter DSL, Hello World example, running a simple test, and more.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>What is a Domain Specific Language?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Here is the definition from Wikipedia: A&nbsp;<strong>domain-specific language</strong>&nbsp;(<strong>DSL</strong>) is a&nbsp;<a href="https://en.wikipedia.org/wiki/Computer_language">computer language</a>&nbsp;specialized in a particular application&nbsp;<a href="https://en.wikipedia.org/wiki/Domain_(software_engineering)">domain</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To simply put, DSL provides some sort of abstraction which solves certain problems. E.g. <a href="https://www.youtube.com/playlist?list=PLJ9A48W0kpRLorIGHOM7g2OUsO2de3ERm" target="_blank" rel="noreferrer noopener">regular expressions</a>, HTML, and more. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you are into <a href="https://www.youtube.com/playlist?list=PLJ9A48W0kpRJE6s8I1MjWm-z8BGbUYNCw" target="_blank" rel="noreferrer noopener">Gatling</a>, then you are already working on DSL. You can also create your own DSL using the <strong>Meta Programming System</strong>, a topic for another blog.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>What is JMeter DSL?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><a href="https://github.com/abstracta/jmeter-java-dsl" target="_blank" rel="noreferrer noopener">JMeter DSL</a> is an open source initiative from Abstracta which provides JMeter-as-Code in Java.  </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here are a couple of drawbacks of vanilla JMeter is: </p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>It is not Git friendly due to its XML nature.</li><li>For Groovy scripting, no autocomplete or debugging feature</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>JMeter DSL solves the above problems, and provides more features such as CI/CD integration, Git and IDE friendly, extends the JMeter ecosystem and makes it more pluggable, and more  </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Hello World on JMeter DSL</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>No more theory. Let us get started with a simple example of JMeter DSL.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Prerequisites</strong></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Basic <a href="https://www.youtube.com/playlist?list=PLJ9A48W0kpRIjLkZ32Do9yDZXnnm7_uj_" target="_blank" rel="noreferrer noopener">JMeter knowledge</a> </li><li>Basic Java knowledge,</li><li>favorite Java IDE</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>In this example, we are going to create a Gradle project using IntelliJ IDEA Community Edition. If you are using other IDEs, instructions would be similar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Launch IntelliJ IDEA and create a new Gradle project as shown below.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9329,"sizeSlug":"full","linkDestination":"media"} -->
<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/04/image-13.png"><img src="https://qainsights.com/wp-content/uploads/2022/04/image-13.png" alt="Getting Started with JMeter DSL - Create Gradle Project" class="wp-image-9329"/></a><figcaption>Getting Started with JMeter DSL - Create Gradle Project</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Copy and paste the below code into the <code>build.gradle</code> file. Your IDE may suggest using the latest version of <code>028</code> for JMeter DSL. This issue has already been <a href="https://github.com/abstracta/jmeter-java-dsl/issues/110" target="_blank" rel="noreferrer noopener">raised</a>. Please ignore that suggestion as of now. It will be fixed in JMeter DSL 1.0. </p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>plugins {
    id 'java'
}

group 'org.qainsights'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
    testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.22.0'

    testImplementation 'us.abstracta.jmeter:jmeter-java-dsl:0.54'

    components {
        withModule("org.apache.jmeter:ApacheJMeter_core", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter_java", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter_http", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter_functions", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter_components", JmeterRule)
        withModule("org.apache.jmeter:ApacheJMeter_config", JmeterRule)
        withModule("org.apache.jmeter:jorphan", JmeterRule)
    }
}

test {
    useJUnitPlatform()
}

// this is required due to JMeter open issue: https://bz.apache.org/bugzilla/show_bug.cgi?id=64465
@CacheableRule
class JmeterRule implements ComponentMetadataRule {
    void execute(ComponentMetadataContext context) {
        context.details.allVariants {
            withDependencies {
                removeAll { it.group == "org.apache.jmeter" &amp;&amp; it.name == "bom" }
            }
        }
    }
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The above Gradle will add the dependencies such as JUnit, AssertJ Fluent Assertions, and optionally, you can add Log4j.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a new Java class called <code>HelloWorldTest</code> in <code>src\test\java</code> folder and import the below directives. </p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import org.junit.jupiter.api.Test;
import us.abstracta.jmeter.javadsl.core.TestPlanStats;

import java.io.IOException;
import java.time.Instant;

import static us.abstracta.jmeter.javadsl.JmeterDsl.*;

public class HelloWorldTest {

}
</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>In this example, we are going to build a simple JMeter test plan with the following elements:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>a Thread Group with 1 thread and 1 iteration,<ul><li>an HTTP Sampler to get https://example.com,<ul><li>an assertion to validate the response message, <code>Example Domain</code></li></ul></li></ul></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Here is the actual JMeter visualization:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9330,"sizeSlug":"full","linkDestination":"media"} -->
<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/04/image-14.png"><img src="https://qainsights.com/wp-content/uploads/2022/04/image-14.png" alt="Target test plan" class="wp-image-9330"/></a><figcaption>Target test plan</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Copy and paste the below block of code into the <code>HelloWorldTest</code> class.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>    @Test
    public void testHelloWorld() throws IOException {

        TestPlanStats helloWorld = testPlan(
                threadGroup(1,1,
                        httpSampler("https://example.com")
                                .children(
                                        responseAssertion().containsSubstrings("Example Domain")
                                )
                ),
                jtlWriter("HelloWorld" + Instant.now().toString().replace(":","-") + ".jtl")
        ).run();
    }</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>As you observe above, the code is self-explanatory. We are defining a new TestPlanStats called <code>helloWorld</code> which will hold the test plan with one thread group.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>That thread group will have one HTTP Sampler hitting https://example.com and which has one childeren to verify the response <code>Example Domain</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>jtlWriter</code> logs the performance status and creates a unique <code>*.jtl</code> file in the current directory.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>.run()</code> method will execute the test plan as per the thread configuration.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To execute, either right click anywhere in the code and run or click on Run button as shown below.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9331,"sizeSlug":"full","linkDestination":"media"} -->
<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/04/image-15.png"><img src="https://qainsights.com/wp-content/uploads/2022/04/image-15.png" alt="Run JMeter DSL" class="wp-image-9331"/></a><figcaption>Run JMeter DSL</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Here is the output. *.jtl file will have the performance stats.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":9332,"sizeSlug":"full","linkDestination":"media"} -->
<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://qainsights.com/wp-content/uploads/2022/04/image-16.png"><img src="https://qainsights.com/wp-content/uploads/2022/04/image-16.png" alt="JMeter DSL Results" class="wp-image-9332"/></a><figcaption>JMeter DSL Results</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Congratulations! Now you have completed writing DSL in Java for JMeter. Now, we can hook this code into JMeter engine to run distributed tests across multiple hosts or put it on the cloud. But, please do not hit example.com with the load, replace it with your application under test URL.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Features of DSL</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>DSL is under active development. The team also released JMeter to DSL converter (work in progress). I will write another blog article featuring the converter. DSL comes with loads of features such as advanced thread group configuration, debugging, reporting, extractions, logical controllers and more.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Use the below code snippet which will launch the GUI for validation purpose.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>testPlan(
                threadGroup(1,1,
                        httpSampler("https://example.com")
                                .children(
                                        responseAssertion().containsSubstrings("Example Domain")
                                )
                ),
                jtlWriter("HelloWorld" + Instant.now().toString().replace(":","-") + ".jtl")
        ).showInGui();</code></pre>
<!-- /wp:code -->

<!-- wp:image {"align":"center","id":9335,"sizeSlug":"large","linkDestination":"media"} -->
<div class="wp-block-image"><figure class="aligncenter size-large"><a href="https://qainsights.com/wp-content/uploads/2022/04/image-17.png"><img src="https://qainsights.com/wp-content/uploads/2022/04/image-17-1024x494.png" alt="JMeter DSL to GUI" class="wp-image-9335"/></a><figcaption>JMeter DSL to GUI</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>JMeter DSL is also powered by third party integrations like Elasticsearch, InfluxDB, and more.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To save the DSL as JMX, use the below code which will convert the DSL to JMX in the current directory.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>        testPlan(
                threadGroup(1,1,
                        httpSampler("https://example.com")
                                .children(
                                        responseAssertion().containsSubstrings("Example Domain")
                                )
                ),
                jtlWriter("HelloWorld" + Instant.now().toString().replace(":","-") + ".jtl")
        ).saveAsJmx("HelloWorld.jmx");</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2>Final Thoughts</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>JMeter DSL is an excellent initiative and welcomes doors to more developers as well as test engineers. JMeter-as-Code opens another multiverse which will break the legacy XML format into more developer-friendly, Git and IDE friendly, gels with the CI/CD pipeline naturally,  and more. Developers must know how JMeter works, its execution order, scoping rules and more. Test engineers must know Java to get started. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As JMeter is heavy on the resource side, JMeter DSL inherits the same problem. It's too early to talk about Project Loom in JMeter ecosystem.  </p>
<!-- /wp:paragraph -->