Pretty straight-forward requirement in JMeter 4.0. Run simple test in jmeter and send email if it fails. So I have this:
>ThreadGroup
>Http Request
>Response Assertion
>Summary Report
>BeanShell Listener
>If Controller
>SMTP Sampler
So, it appears the best way to exercise the SMTP Sampler is to use the JMeterThread.last_sample_ok variable. I am testing this variable in the BeanShell Listener and it works. If I shut down the REST service I'm testing, I can see that the variable is false and if I start the service, it returns true. Perfect. In the If Controller, when I enter JMeterThread.last_sample_ok I receive an email when the service is on. Great...working as it should. PROBLEM: When I shut down the service so that the assertion fails and I change the If Controller to the inverse: !JMeterThread.last_sample_ok, I never get an email. The If Controller seems to never respond when the failed assertion is expected and I never get my email. I can show that the variable is translating correctly in the BeanShell Listener...I can see that in the failure case, !JMeterThread.last_sample_ok translates to "true" and so this same code in the If Controller should work. What am I doing wrong? Here is the XML file...
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="AddressValidation Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="AddressValidation Request" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">{
"address": {
"address2": "1625",
"city": "austin",
"address1": "4701 Staggerbrush Rd",
"zip4": "",
"state": "tx",
"zip5": "78749"
}
}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">9095</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/address-standardization</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Content-Type</stringProp>
<stringProp name="Header.value">application/json</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="-1781066058">{"address":{"address1":"APT 1625","address2":"4701 STAGGERBRUSH RD","city":"AUSTIN","state":"TX","zip5":"78749","zip4":"1048"}}</stringProp>
</collectionProp>
<stringProp name="Assertion.custom_message"></stringProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">16</intProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="AddressValidation Response" enabled="true">
<boolProp name="ResultCollector.error_logging">true</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename">C:\test\reports\response_out.csv</stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">true</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>false</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>false</threadName>
<dataType>false</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename">C:\test\reports\AddressValidation.jtl</stringProp>
</ResultCollector>
<hashTree/>
<BeanShellListener guiclass="TestBeanGUI" testclass="BeanShellListener" testname="BeanShell Listener" enabled="true">
<stringProp name="filename"></stringProp>
<stringProp name="parameters"></stringProp>
<boolProp name="resetInterpreter">false</boolProp>
<stringProp name="script">log.debug( "should_be_false=" + !${JMeterThread.last_sample_ok} );
</stringProp>
</BeanShellListener>
<hashTree/>
<IfController guiclass="IfControllerPanel" testclass="IfController" testname="If Controller" enabled="true">
<stringProp name="IfController.condition">!${JMeterThread.last_sample_ok}</stringProp>
<boolProp name="IfController.evaluateAll">true</boolProp>
<boolProp name="IfController.useExpression">true</boolProp>
</IfController>
<hashTree>
<SmtpSampler guiclass="SmtpSamplerGui" testclass="SmtpSampler" testname="SMTP Sampler" enabled="true">
<stringProp name="SMTPSampler.server">ezmail-out.xyz.com</stringProp>
<stringProp name="SMTPSampler.serverPort">25</stringProp>
<stringProp name="SMTPSampler.mailFrom">[email protected]</stringProp>
<stringProp name="SMTPSampler.replyTo"></stringProp>
<stringProp name="SMTPSampler.receiverTo">[email protected]</stringProp>
<stringProp name="SMTPSampler.receiverCC"></stringProp>
<stringProp name="SMTPSampler.receiverBCC"></stringProp>
<stringProp name="SMTPSampler.subject">AddressValidation Test Result</stringProp>
<stringProp name="SMTPSampler.suppressSubject">false</stringProp>
<stringProp name="SMTPSampler.include_timestamp">true</stringProp>
<stringProp name="SMTPSampler.message"></stringProp>
<stringProp name="SMTPSampler.plainBody">false</stringProp>
<stringProp name="SMTPSampler.attachFile">C:\test\reports\AddressValidation.jtl</stringProp>
<stringProp name="SMTPSampler.useSSL">false</stringProp>
<stringProp name="SMTPSampler.useStartTLS">false</stringProp>
<stringProp name="SMTPSampler.trustAllCerts">false</stringProp>
<stringProp name="SMTPSampler.enforceStartTLS">false</stringProp>
<stringProp name="SMTPSampler.useLocalTrustStore">false</stringProp>
<stringProp name="SMTPSampler.trustStoreToUse"></stringProp>
<boolProp name="SMTPSampler.use_eml">false</boolProp>
<stringProp name="SMTPSampler.emlMessageToSend"></stringProp>
<stringProp name="SMTPSampler.useAuth">false</stringProp>
<stringProp name="SMTPSampler.password"></stringProp>
<stringProp name="SMTPSampler.username"></stringProp>
<stringProp name="SMTPSampler.messageSizeStatistics">false</stringProp>
<stringProp name="SMTPSampler.enableDebug">false</stringProp>
<collectionProp name="SMTPSampler.headerFields"/>
</SmtpSampler>
<hashTree/>
</hashTree>
</hashTree>
<PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</PostThreadGroup>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>
Well, this is because at the moment you add boolean operator !
, your condition can no longer be Interpreted as Variable Expression. Instead it needs to be evaluated using language (javascript by default).
In other words, if you check the Interpret Condition as Variable Expression
checkbox, condition is compared to word true
- that's it! If you add exclamation mark in front of it, it will become !true
and will fail.
You have several options:
Uncheck Interpret Condition as Variable Expression
, so that condition is evaluated using JavaScript. But as documentation states, there's a performance penalty for that.
Reverse your Response Assertion condition, so that it fails when there's no need to send email. That way you keep If Controller to simple ${JMeterThread.last_sample_ok}
You can also create custom variable in Http Request post-processor which will take a value opposite of assertion, but will evaluate to true
or false
. Use that variable in If Controller.
Amend your If Controller's condition to use __groovy() function like:
${__groovy(vars.get('JMeterThread.last_sample_ok').equals('false'),)}
Also be aware that according to JMeter Best Practices Beanshell scripting is an antipattern (as well as inlining JMeter functions into scripts) so consider migrating to JSR223 Listener and Groovy language and access JMeter Variables using vars
shorthand which stands for JMeterVariables class instance
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With