JMeter: A Data-Driven Test Script - Part 1

In this post and the next I'm going to break down a JMeter script that illustrates a simple data-driven test technique and some of JMeter's components.  The first part will focus on the structure of the script, covering some key logic and configuration controllers; since they warrant a little more attention, the second part will look at the script's request samplers and closely associated components. The script (JMeter script files have a JMX extension) and csv data file used by the script are available for download here in a single zip file.  After unzipping the files, open the JMX file in JMeter (File - Open in the file menu).  By default, the csv file is expected to be in a folder called C:\Temp\PerTableData, but you can put it anywhere you'd like as long as you modify the CSV Data Controller accordingly.

Here's what the script tree should look like once you've opened it:


To see the script in action, click on the node for the View Results Tree listener (where it's easiest to see the script's progress), then click on the Play button at the top of JMeter's main window (the button with the large green arrow).  The script runs against a web service that provides data about the periodic table of elements.  There are four methods provided by the service, which are split into two groups in the script-- three of the methods are element specific (they return data based on an individual element provided as a parameter) and the last simply returns a list of all the elements in the periodic table (if you've read my post on data driven testing in soapUI, this should all look very familiar-- this script runs against the same service and is similarly structured).

Since this is strictly a functional test script, we only need a single user configured in the Test User element at the top of the script:


The HTTP Request Defaults config element at the top of the script specifies a default server, path, etc., to use for request samplers.  Since it's placed at the top of the tree, it's applied to all requests; however, you can override these default values by specifying different values locally (within an individual request's own configuration dialog).  One potential "gotcha" to note: the server name field in this element does not take a full URL-- the "http://" prefix should be omitted when specifying the server.


The "Duration LT 5 Sec" Duration Assertion asserts that all requests should complete within 5000 milliseconds (5 seconds).  As with the HTTP defaults element, its placement at the topmost level of the script tree means it's applied to all requests.


The "ElementRequests Loop" Loop Controller establishes a "branch" to the tree that loops indefinitely (an If Controller placed within the loop will terminate it based on our source data):


Within our loop, the first element is a CSV Data Set Config element:


The element specifies the location of our source CSV file to use to read in variable values-- if you put this file somewhere other than the default location, you'll have to change the Filename entry here.  It also specifies the variable names we're going to use in our script-- each variable name corresponds to a column in our CSV file-- so the first item in each row is assigned to the ElName variable, the second item is assigned to the ElNum variable, etc.  Note that we don't have to do any additional work to manage reading this file-- no maintaining a separate counter to keep our place, for example-- each time it's encountered in our loop, JMeter reads in the next line.  Although we're not using it in this case (we only have one user configured), note that you can "share" data from the CSV file between multiple threads/virtual users via the "Sharing mode" options-- meaning each time any thread encounters the CSV file in its execution, it reads the next line.  So you could have one thread read in data from row 1, the next thread read in data from row 2, etc.

To prevent the loop from running indefinitely, our test requests are nested beneath an If Controller that checks to see if the end of our CSV file has been reached.


When JMeter attempts to read in data from our CSV file after it's already read in the last row, "<EOF>" is returned.  That serves as a flag that it's time to exit the loop-- or more specifically, when "<EOF>" is not returned as the value of the ElName variable, that serves as a flag that it's okay to continue to execute our requests.  The condition statement illustrates how to reference variables: enclose the name in braces and precede it with "$" (remember that our variable names were configured in the CSV Config element).  Note that in our condition statement ("${ElName}"!="<EOF>") the name of our string variable is enclosed in quotes-- this syntax may seem unusual to some; see JMeter's component reference for some more condition statement examples.

Skipping the request samplers and related config elements for now (again, we'll look at those in the next post), the script contains two listener components which collect and report run data.  The Results Tree listener shows request and response data in detail-- even if you don't intend to use this listener in your finalized script, it's good for troubleshooting when you're building a script, allowing you to see exactly what's sent and received and create your assertions accordingly.


In the next post we'll look specifically at the script's request samplers and compare the deprecated SOAP Request sampler with the HTTP Request sampler.

6 comments:

  1. do you have to have soapUI installed to run this demo?

    ReplyDelete
  2. No, that shouldn't be the case; JMeter's a separate tool. I only referenced soapUI in this post for comparison; this demo tackles a problem similar to what I tackled in a post on soapUI. Sorry if I caused any confusion.

    ReplyDelete
  3. Thank you Mike for your reply. Your test plan works, however the "get atoms" does not, so I am investigating...

    ReplyDelete
  4. I just re-downloaded the script and tried it myself and that request does seem to work for me-- actually, the GetAtoms request is relatively simple (there are no parameters in the request), so it's odd that that one isn't working for you. Is the request completely failing (unable to get any response or getting an error) or are you getting a valid response but the response is failing an assertion (you can see in the Assertion Results component where any assertion failures are happening)? There's a time-based assertion which will fail if a response takes longer than 5 seconds; occasionally I see that's failing for me.

    ReplyDelete
  5. Hi,
    I want to access the csv file as per the api and need to put condition if it satisfies then will access that particular line from csv file.Please advise.
    eg: api_1 and api_2 in the thread group and CSV file is comman for both but data present in csv line1 for api_1 and line2 for api_2. how will make it access as per api basis.

    ReplyDelete
  6. I'm not sure I'm following what you want to do precisely-- do you definitely need a conditional statement, or are you just trying to tie different lines from your CSV file to different threads and think that might be a way to do it? I believe this is actually the default behavior for the CSV Data Set Config controller (see section 18.4.1 of the online JMeter User Manual). If the Sharing Mode for the file is set to "All Threads", then each thread reads one line of the file-- thread one would read line 1, thread two would read line 2, etc. The "Current Thread" mode would result in each thread reading each line of the file-- thread one would read line 1, thread two would read line 1, then they'd both move to line 2, etc.

    You may also want to look at the User Parameters element (section 18.7.5 in the manual), which is specifically designed to assign variable values across different threads.

    ReplyDelete

Please be respectful of others (myself included!) when posting comments. Unfortunately, I may not be able to address (or even read) all comments immediately, and I reserve the right to remove comments periodically to keep clutter to a minimum ("clean" posts that aren't disrespectful or off-topic should stay on the site for at least 30 days to give others a chance to read them). If you're looking for a solution to a particular issue, you're free to post your question here, but you may have better luck posting your question on the main forum belonging to your tool's home site (links to these are available on the navigation bar on the right).