JMeter

API Testing and more

Created by Kavan Sheth



Best viewed in Chrome, Firefox, Opera or A browser supporting HTML5. Use arrow keys ( up ↑, down ↓, left ←, right ↑) to navigate. Uses Reveal.js by Hakim El Hattab Press ESC to enter the slide overview.

Introduction

  • JMeter is one of the best open source tool for load testing. Initially it was intended for Web Applications but gradually extended for load testing of WebServices, Java Objects, Data Bases and Queries, FTP Servers etc.
  • While working with JMeter main issue can be the terminology used. Different component names like ThreadGroup, Sampler, Listeners, Controllers may sound strange initially but believe me is not as hard as it seems.
  • Check out glossary below to get accustom with JMeter

Glossary

  • Test Plan : The Test Plan is where the overall settings for a test are specified.
  • Thread Group : A Thread Group defines a pool of users that will execute a particular test case against your server. In the Thread Group GUI, you can control the number of users simulated (num of threads), the ramp up time (how long it takes to start all the threads), the number of times to perform the test, and optionally, a start and stop time for the test.
  • Controllers : Logic Controllers determine the order in which Samplers are processed.
  • Sampler : Samplers perform the actual work of JMeter. Each sampler (except Test Action) generates one or more sample results. The sample results have various attributes (success/fail, elapsed time, data size etc) and can be viewed in the various listeners.
  • Listener : Most of the listeners perform several roles in addition to "listening" to the test results. They also provide means to view, save, and read saved test results. Note that Listeners are processed at the end of the scope in which they are found.
  • Workbench : The WorkBench simply provides a place to temporarily store test elements while not in use, for copy/paste purposes, or any other purpose you desire. When you save your test plan, WorkBench items are not saved by default.
These definitions directly taken from JMeter Help. You can get much more details in Help Document.

Glossary-Simplified

  • Test Plan : Your Test Case Holder
  • Thread Group : Simulates No. of Users and User Behaviour
  • Controllers : For Flow control of your Test Case (If... Else, Looping, Switch and Many More) .
  • Sampler : Does actual Task of Sending Requests and Provides test result for the Listeners.
  • Listener : Listen to the test results, Display result, Save results, and Read saved test results.
  • Workbench : Temporary Storage Area.

Send a SOAP Request




Installation

Scenario

  • Here we will be sending a simple SOAP request and see how to view result.
  • We will be using TestPlan(default), a ThreadGroup(Sampler can exists only within a ThreadGroup), SOAP/XML-RPC Request(Sampler) and View Results Tree(Listener).
  • To add a component just right click on parent component and add required component under it.

Test Plan

Thread Group

SOAP/XML-RPC Request(Sampler)

SOAP/XML-RPC Request(Sampler)

SOAP/REST Request using HTTP Sampler




SOAP Request using HTTP Request Sampler

REST Request using HTTP Request Sampler

Is it enough?

  • Did you run the requests, does it work?
  • I guess you must be getting failure as I did.
  • So let's see the Request in "View Results Tree" Listener, is all data being sent correctly
  • Request XMLs seems OK. isn't it?
  • Let's check header part
  • It wasn't that obvious
  • With some Googling found that for SOAP/REST Content Type should be text/xml and not as following:
  • Content-Type: application/x-www-form-urlencoded
  • So let's change Content-Type Header Parameter, for that we will need Config Element "HTTP Header Manager"

Config Element- HTTP Header Manager


Once HTTP Header Manager is added to ThreadGroup, Both SOAP and REST request should be successful.

SOAP Request with WS-Security




Sending Username and Timestamp token

In some project, we needed to send request with WS-Security tokens UserName and Timestamp, which can be done easily with SoapUI.

While searching for a way to send WS-Security Header with request, couldn't find a straight forward way

But a Post(ReadMe.pdf) from Nirodha at here, suggested a good way.

Following Security Header was expected in SOAP request:

<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
	<wsu:Timestamp>
			<wsu:Created>2015-05-26T18:48:48Z</wsu:Created>
			<wsu:Expires>2015-05-26T18:48:50Z</wsu:Expires>
	</wsu:Timestamp>
	<wsse:UsernameToken wsu:Id="UsernameToken-4">
			<wsse:Username>rkadm</wsse:Username>
			<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">rkadm</wsse:Password>
			<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MTQzMjY2NjEyODM3Mw==</wsse:Nonce>
			<wsu:Created>2015-05-27T00:18:48.374Z</wsu:Created>
	</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>

Sending Username and Timestamp token

  • Here, we need to send Created, Expires under TimeStamp token and Nonce and created under Username token, which needs to be changed with each request.
  • So what can be done?
  • JMeter provides a very useful components BeanShell PreProcessor/PostProcessor/Assertion/Timer.
  • What is BeanShell? - "BeanShell is a small, free, embeddable Java source interpreter with object scripting language features, written in Java. BeanShell dynamically executes standard Java syntax and extends it with common scripting conveniences such as loose types, commands, and method closures like those in Perl and JavaScript."

Use BeanShell

Here idea is to plug specific strings to XML request, and replace them with actual timestamps and nonce generated in BeanShell PreProcessor

So Request need to be modified like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:car="http://soap.crmapi.util.redknee.com/cardpackages/xsd/CardPackages-v2.0" xmlns:ns="http://soap.crmapi.util.redknee.com/common/xsd/2011/05" xmlns:ns1="http://soap.crmapi.util.redknee.com/common/xsd/2008/08">
  <soapenv:Header>
   <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsu:Timestamp>
				<wsu:Created>#timeC#</wsu:Created>
				<wsu:Expires>#timeE#</wsu:Expires>
			</wsu:Timestamp>
			<wsse:UsernameToken wsu:Id="UsernameToken-4">
				<wsse:Username>rkadm</wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">rkadm</wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">#nonce#</wsse:Nonce>
				<wsu:Created>#UTtimeC#</wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soapenv:Header>	
   <soapenv:Body>
      <car:getCardPackage>
         <car:header>
            <ns:password>rkadm</ns:password>
            <ns:username>rkadm</ns:username>
         </car:header>
         <car:packageID>7700000001</car:packageID>
      </car:getCardPackage>
   </soapenv:Body>
</soapenv:Envelope>

Use BeanShell

Added a BeanShell PreProcessor to project and following BeanShell generates required token and adds it to HTTP request POST body:

import org.apache.jmeter.protocol.http.sampler.WebServiceSampler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import org.apache.commons.codec.binary.Base64;

try{
// generating NONCE
String time= new Long(System.currentTimeMillis()).toString();
String nonce = new String(Base64.encodeBase64(time.getBytes("US-ASCII")));

// generating relevant Timestamps
long ctmilli = System.currentTimeMillis(); 
SimpleDateFormat dformat1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); 
SimpleDateFormat dformat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); 
Date dtime = new Date();
dformat1.setTimeZone(TimeZone.getTimeZone("UTC"));
dtime.setTime(ctmilli); 
String timeCreated = dformat1.format(dtime); 
String uttimeCreated = dformat2.format(dtime); 
dtime.setTime(ctmilli+2000); 
String timeExpire = dformat1.format(dtime); 

// to embed the security elements into
String modRequest= sampler.getArguments().getArgument(0).getValue().replaceFirst("#timeC#", timeCreated);
modRequest = modRequest.replaceFirst("#timeE#", timeExpire); 
modRequest = modRequest.replaceFirst("#nonce#", nonce); 
modRequest = modRequest.replaceFirst("#UTtimeC#", uttimeCreated);
sampler.getArguments().getArgument(0).setValue(modRequest) ; 
}
catch (Throwable ex) {
    log.error("Failed to do this or that", ex);
}

Store and Access Variables from Sampler




Record HTTP requests using BadBoy




a Very Good BadBoy

  • BadBoy is free(Conditional - Read license doc before commercial use) tool to record HTTP request made while performing user activities.
  • Irrespective of what user does, what browser does at the end is send HTTP request and receive a response(it can be the same page(page refresh), or a different page).
  • So what BadBoy does is provide capability to capture this HTTP request made by browser and allow it to export as JMeter script.
  • BadBoy can be downloaded from here

Use Case for Recording

  • We will be using http://newtours.demoaut.com for test purpose
  • 1. Access http://newtours.demoaut.com page
  • 2. Click Register, so registration page will be retrieved.
  • 3. Click on Submit, success page will be retrieved.

Recording

So once you are done with recording, it will look something like following in BadBoy

Once test activity recorded, just go to file menu and choose Export to JMeter. It will generate .jmx file with desired HTTP requests.

Use Recorded Script in JMeter

Once recording is exported to .jmx file, it can be opened as a JMeter project and without making much changes(Here I have just added Listeners) it will be in ready to run state.