The JMeter Pre-Processor Explained
A beginner-friendly but production-minded guide to the elements that get every request ready just before it leaves, so that your virtual users behave like real people instead of identical robots.
Picture a chef in a busy restaurant kitchen. Before the first order arrives, the chef chops onions, measures spices, and lines up pans. Cooks call this preparation mise en place, which is French for “everything in its place”. When an order comes in, the chef does not stop to find a knife. Everything is ready, so the dish leaves the kitchen quickly and correctly.
A load test has the same need. When JMeter is about to send a request, it often needs something prepared first: a different user name for each virtual user, a fresh session token, a value fetched from a database, a timestamp, or a small change to the address being called. If every virtual user sent exactly the same fixed request, the test would look nothing like real traffic, and many systems would reject or cache the repeated requests. The elements that do this last-minute preparation are called Pre-Processors.
This guide teaches Pre-Processors from zero. You will learn what they are, where they run, how far their reach extends, and the main members of the family. Then we go deeper into how they work internally, how variables travel, how to choose between similar elements, and what separates a beginner script from a production-quality test: performance, scalability, monitoring, security, design patterns, anti-patterns, and troubleshooting. Every new term is explained the first time it appears, and every big idea comes with an everyday comparison.
WWhat Is a Pre-Processor?
A Pre-Processor is a small helper that runs just before a request is sent.
Apache JMeter is a free, open-source tool from the Apache Software Foundation. It pretends to be many users at the same time and measures how a system behaves under that crowd. A JMeter test is described by a test plan, which is a tree of small building blocks called elements. Some elements send requests, and these are called samplers. A Pre-Processor is an element that does some work immediately before a sampler runs.
The simple definition
A Pre-Processor prepares the ground for a sampler. It can set or change variables, modify the request that is about to be sent, fetch data from somewhere, or apply a limit. Whatever it does, it does it after the plan has decided that a sampler will run, and before the sampler actually sends anything.
Think of an actor in a theatre. Before walking on stage, the actor visits the dressing room for costume and makeup. The audience never sees that room, but it changes how the actor appears. A Pre-Processor is the dressing room of a request.
What it is not
A Pre-Processor is not a sampler, so it does not send requests of its own and it does not appear as a row in the results. It is also not a Post-Processor, which does its work after the response comes back. And it is not a Config Element, which supplies defaults and data sources. The next chapters show how these neighbours differ, because confusing them is the most common beginner problem.
A variable in JMeter is a named value that belongs to one virtual user. You write it as a name inside a dollar sign and curly brackets, and JMeter replaces it with the current value when a request is sent. Most Pre-Processors work by setting variables.
WWhy We Need to Prepare Before a Request
Real users are all different, and a test full of identical users proves very little.
Imagine a thousand customers visiting an online shop. Each one signs in with their own account, receives their own session, adds different items, and sends different addresses. If a test sends the same account name a thousand times, strange things happen. The shop may lock the account, return cached answers, or follow a shortcut that real traffic never takes. The result looks like a test, not like life.
Four reasons to prepare a request
Unique identity
Each virtual user needs their own name, password, or account number, so the system sees many people instead of one.
Fresh values
Many requests carry values that must be new each time, such as a time stamp, a random number, or an order reference.
Values from earlier steps
An earlier reply may hold a token or session identifier that the next request must send back.
Limits and guards
Sometimes the preparation is a safety net, such as a maximum waiting time for a request that might hang.
What goes wrong without preparation
Without preparation the test may report excellent speed for the wrong reasons. Cached answers come back in a blink. Repeated sign-ins hit a shortcut. A request with an expired token returns a fast error. In each case the numbers look good while the test has quietly stopped measuring what users really do.
Test with preparation
- Each virtual user behaves like a different person
- Caches and shortcuts are used as in real life
- Tokens and identifiers stay valid
- Results reflect real server work
Test without preparation
- All users look identical to the server
- Caches make responses unrealistically fast
- Expired or reused values cause hidden errors
- Results flatter the system
Teams that run large tests often find that the first draft of a script is far too uniform. Adding preparation steps is usually the biggest single step towards a realistic test.
WWhere Pre-Processors Fit in the Order of Execution
JMeter runs element types in a fixed order, and Pre-Processors come early.
When a sampler is about to run, JMeter does not simply go from top to bottom through the tree. It follows a fixed order by element type. According to the JMeter documentation, the order for each sampler is: Configuration Elements first, then Pre-Processors, then Timers, then the Sampler itself, then Post-Processors, then Assertions, and finally Listeners.
flowchart LR
A["Config Elements"] --> B["Pre-Processors"]
B --> C["Timers"]
C --> D["Sampler sends the request"]
D --> E["Post-Processors"]
E --> F["Assertions"]
F --> G["Listeners"]
Think of mailing a parcel. First you gather the materials, then you wrap the parcel, then you wait in the queue at the post office, then you hand it over. After that comes the receipt check and the record keeping. The wrapping must happen before the handing over, whatever order you happened to pick up the tape and paper in.
Two important consequences
- Position in the tree does not change the type order. A Pre-Processor written below a sampler in the tree still runs before that sampler, as long as it is in scope.
- Nothing runs without a sampler. Pre-Processors, Timers, Post-Processors and Assertions are only processed when there is a sampler they apply to. An element with no sampler in its scope does nothing.
| Step | Element type | Plain meaning |
|---|---|---|
| 1 | Config Elements | Set defaults and supply data |
| 2 | Pre-Processors | Prepare this particular request |
| 3 | Timers | Pause before sending |
| 4 | Sampler | Send the request and wait for the answer |
| 5 | Post-Processors | Study the answer and capture values |
| 6 | Assertions | Check that the answer is correct |
| 7 | Listeners | Display or save the result |
Because Config Elements run before Pre-Processors, a Pre-Processor cannot change what a Config Element has already done for this sampler. If you need a value in place before a Config Element, set it earlier, for example in a previous step or in a setup stage.
SScope: Which Samplers Get Prepared
Position in the tree decides how many requests a Pre-Processor serves.
A test plan is a tree. At the top is the Test Plan, under it are thread groups, which are the crowds of virtual users, and below those sit controllers and samplers. You add a Pre-Processor by right-clicking an element and choosing Add, then Pre Processors. The element you right-click becomes its parent, and the parent decides its scope, the set of samplers it prepares.
flowchart TD
TP["Test Plan"] --> TG["Thread Group"]
TG --> P0["Pre-Processor at group level: runs before every sampler in the group"]
TG --> S1["Sampler: Home Page"]
TG --> C1["Controller: Checkout Steps"]
C1 --> P1["Pre-Processor under the controller: runs before each sampler inside it"]
C1 --> S2["Sampler: Add Address"]
C1 --> S3["Sampler: Pay"]
S3 --> P2["Pre-Processor under one sampler: runs only before Pay"]
| Where it is placed | Which samplers it prepares | Typical use |
|---|---|---|
| As a child of one sampler | Only that sampler | A special value needed by one request |
| Under a controller | Every sampler inside that controller | Preparation shared by a group of steps |
| Under a thread group | Every sampler in that group | Preparation for the whole user journey |
| Directly under the Test Plan | Every sampler in every group | A global rule, used with great care |
Wide scope is convenient and costly
A Pre-Processor with a wide scope runs again and again, once before every sampler in its reach. If it does heavy work, such as a database query, that work repeats for every single request. Place each Pre-Processor as close as possible to the samplers that truly need it.
A school rule posted at the front gate applies to every classroom. A note on one classroom door applies to that room only. A rule on a single desk applies to one child. Wider rules are easy to write but affect many more people.
TThe Family of Pre-Processors
The Pre Processors menu holds several tools, each with a different job.
When you open the menu, you will see a short list of Pre-Processors. The exact list depends on your JMeter version, but the main members have been stable for many years. Here is a first overview before we study each one.
User Parameters
Gives each virtual user its own set of variable values from a small table you fill in.
RegEx User Parameters
Builds variables from the results of a regular expression extractor, matching names and values.
HTTP URL Re-writing Modifier
Adds a session identifier to web addresses when a site keeps the session in the address instead of in a cookie.
JDBC PreProcessor
Runs a database statement before the sampler and can store the result in variables.
JSR223 PreProcessor
Runs a short script written in a supported language to do any custom preparation.
BeanShell PreProcessor
An older scripting option that is generally recommended against in favour of JSR223.
Sample Timeout
Interrupts a sampler that runs longer than a time you set.
HTML Link Parser
Reads links from the previous response and uses one of them for the next request.
A kitchen drawer holds a peeler, a grater, a whisk, and a timer. You never use all of them for one dish, and you would not peel an onion with a whisk. Pre-Processors are kitchen tools: choose the one that fits the task.
If you are unsure which tool to use, start with the simplest one that can do the job. User Parameters or a script-free solution is easier to read and to repair than a custom script.
Menu names and the presence of older elements vary between versions. Check the menu in your own installation, and treat this guide as a map of ideas.
UUser Parameters: Different Values for Different Users
The simplest way to give each virtual user a personal set of values.
The User Parameters element holds a small table. Each row is a variable name, and each column after the name holds the values for one virtual user. When a thread runs, JMeter picks the column that matches that thread and sets the variables to those values. One user might get the name “alice” and another “bob”, from the same element.
How the table works
Name the variables
Add one row for each variable, such as a user name and a city.
Add a column per user
Each extra column holds one set of values. Add as many columns as you want distinct users.
Use the variables
Refer to the variable names in later samplers with the usual dollar-and-brackets form.
Decide when values update
A check box called Update Once Per Iteration controls whether values change on every pass or only once per loop of the thread’s journey.
It works like a seating plan for a wedding. Each guest has a card, and when they arrive they receive the card meant for them. The table of cards is written once, and each guest picks up only their own.
When it is a good choice
- You have a handful of users or values, so a small table is easy to read.
- The values do not need to change while the test runs.
- You want something simple that other team members can understand at a glance.
When there are more virtual users than columns, columns are reused, so several users share the same values. For large numbers of distinct users, a CSV Data Set Config reading a file is usually a better fit.
RRegEx User Parameters: Turning Captured Values into Variables
It reads names and values from an earlier extraction and creates matching variables.
Sometimes a reply contains a whole list of fields that the next request must send back, such as the hidden fields of a web form. Writing one extractor per field is tedious. The RegEx User Parameters element handles this pattern. It looks at the results of an earlier Regular Expression Extractor and turns pairs of captured text into variables.
The three settings that matter
| Setting | What it tells JMeter |
|---|---|
| Regular Expression Reference Name | The reference name of the earlier extractor whose results should be used |
| Parameter names group number | Which group in the match holds the name of each field |
| Parameter values group number | Which group in the match holds the value of each field |
An idea in plain words
Suppose a page contains many hidden fields, each with a name and a value. An extractor captures every pair. This Pre-Processor then creates one variable per pair, named after the field, holding the field’s value. The next request can send all of them without you writing a line for each.
Imagine copying every line of a printed form into a new form with the same boxes. You could write each box by hand, or you could use carbon paper that copies them all at once. This element is the carbon paper.
It depends on an extractor placed earlier, so test the extractor on its own first. If the extractor finds nothing, this element has nothing to turn into variables.
UHTTP URL Re-writing Modifier: Sessions in the Address
When a site keeps your session inside the web address, this element adds it for you.
Most websites remember a visitor using a cookie, which is a small piece of data the browser sends back automatically. JMeter handles cookies through the HTTP Cookie Manager. A few older or special systems instead place a session identifier inside the web address itself. Each page link then ends with a long code that identifies the visitor. If the test does not copy that code into each new address, the server treats every request as a stranger.
What the modifier does
The HTTP URL Re-writing Modifier looks for the session identifier in the previous response, using a name you provide. It then appends that identifier to the addresses of the following requests. You tell it the name of the argument, and optionally whether the identifier is added as a path extension or as an ordinary parameter, and whether to remember it for later use.
Session Argument Name
The name of the session identifier that the site uses in its addresses.
Path Extension
Chooses whether the identifier is attached to the path, in the style used by some Java servers.
Cache Session Id
Remembers the last found identifier, so pages that do not repeat it still receive it.
URL Encode
Encodes special characters in the identifier so the address stays valid.
Think of a cinema ticket that is stamped on your hand instead of kept in your pocket. Each time you enter a screening room you must show the stamp. The modifier carries the stamp from room to room for the virtual user.
Today most systems use cookies or tokens in headers. If your site does, this element is not needed, and adding it only adds work. Check how your application really tracks sessions before choosing it.
JJDBC PreProcessor: Fetching Data from a Database
Run a database statement just before a request and keep the answer in variables.
JDBC stands for Java Database Connectivity, the standard way for Java programs to talk to databases. The JDBC PreProcessor lets a test run a statement against a database right before a sampler, for example to read a fresh order number or to prepare test data. It works together with a JDBC Connection Configuration element, which holds the connection details and gives the connection pool a name.
Main settings in plain words
| Setting | Plain meaning |
|---|---|
| Pool name | Which prepared database connection to use |
| Query type | Whether it reads, writes, or runs a stored routine |
| Query text | The statement to run |
| Variable names | Names for the variables that receive the returned columns |
| Result variable | A variable holding the full result set for later use |
| Query timeout | How long to wait before giving up on the statement |
Before cooking, a chef may phone the warehouse to ask which ingredient is fresh today. The answer decides what goes into the pan. The database call is that phone call, made just before each dish.
Use it with respect
- Point it at a test database, never at real customer data.
- Remember that it runs before every sampler in its scope, so keep the scope small.
- Prefer fetching a block of data once at the start, when the data does not change per request.
- Be aware that database work competes with the system under test if both share a server.
Statements that change data can interfere with each other when many users run at once. Test them with a few users first, and consider whether they could lock rows or create duplicates.
JJSR223 PreProcessor: Custom Preparation with a Script
When nothing else fits, a short script can prepare anything.
JSR223 is a standard that lets Java programs run scripts in other languages. The JSR223 PreProcessor runs a short script before the sampler. The script can read and write variables, build values, compute signatures, pick random entries, or adjust the sampler. The JMeter documentation generally recommends JSR223 with the Groovy language for scripting, because it is fast when its compiled form is cached.
Main settings in plain words
- Language: which scripting language to use. Groovy is the usual choice.
- Parameters: optional text passed to the script, so one script can serve several elements.
- Script file: an optional file to run instead of text typed in the screen.
- Script: the script text itself.
- Cache compiled script: a check box that lets JMeter compile the script once and reuse it, which matters greatly for speed.
A multi-tool pocket knife can do many jobs, but it is slower and clumsier than the right specific tool. A script is the multi-tool of JMeter: flexible, never the first choice when a simple element would do.
When a script is worth it
Good reasons
- A value needs real calculation, such as a signature or a checksum
- Logic depends on several variables at once
- No built-in element offers the needed behaviour
Poor reasons
- You are more comfortable writing code than using the screens
- A built-in element already does the job
- The script is long and nobody else can read it
Keep scripts short, named by purpose, and commented in plain words. A script that only its author understands becomes a risk the day that person leaves.
BBeanShell, Sample Timeout, and HTML Link Parser
Three more members of the family, each with a narrow job.
BeanShell PreProcessor
BeanShell is an older scripting engine that came with JMeter for many years. The BeanShell PreProcessor runs a script before a sampler, much like the JSR223 version. The documentation advises that JSR223 elements are the better choice, mainly because they perform better and are better supported. You will meet BeanShell in older test plans, and it is fine to leave a working one alone, but new work should use JSR223.
Sample Timeout
The Sample Timeout element sets a time limit, in milliseconds, for the sampler it prepares. If the sampler runs longer than the limit, JMeter interrupts it. This is useful when a request might hang forever and you prefer to record a failure and move on. Not every kind of sampler can be interrupted cleanly, so check the behaviour with your own samplers.
A chess clock sets a limit on each move. When the time is up, the move is over, whether the player is ready or not. The Sample Timeout is the chess clock for a request.
HTML Link Parser
The HTML Link Parser reads the links, forms, and images found in the previous response and chooses one of them to fill in the next HTTP request. It is mostly used for simple “click around the site” spidering tests, where you do not know in advance which links exist. It is a blunt instrument, because a random click is not a realistic user journey, so many production tests prefer carefully scripted paths.
| Element | Best for | Limit to remember |
|---|---|---|
| BeanShell PreProcessor | Maintaining older plans | Slower than the recommended JSR223 option |
| Sample Timeout | Stopping requests that might hang | Only works where the sampler can be interrupted |
| HTML Link Parser | Quick random browsing of a site | Random links are not realistic journeys |
A timeout turns an endless wait into a recorded failure, which keeps virtual users flowing. Choose its value from the longest delay a real user would tolerate, not from a guess.
VVariables and Properties: How Pre-Processors Pass Data
Almost every Pre-Processor works by putting a value somewhere that the sampler can read.
JMeter has two main places to keep named values. Variables belong to a single virtual user, which JMeter calls a thread. Properties belong to the whole JMeter program and are shared by every thread. A Pre-Processor usually writes variables, because the preparation is personal to one user’s next request.
| Feature | Variables | Properties |
|---|---|---|
| Who can see the value | Only the thread that set it | Every thread in the test |
| Typical use | User name, token, order number for one user | Settings such as the server name or a global limit |
| How you read it in a request | Dollar sign with curly brackets around the name | A special function that reads a property by name |
| Can it change during the test | Yes, freely, per thread | Possible, but usually set once |
| Risk | Low, because it is private | Higher, because changes affect everyone |
A variable is a note in your own pocket. A property is a notice on the office wall. Notes in a pocket can change as often as you like without bothering anyone, while a change to the wall notice affects every person who reads it.
How the sampler reads what was prepared
When a sampler runs, JMeter looks through its settings for variable references and replaces each one with the current value. This happens at the moment the sampler runs, which is why a Pre-Processor that sets a variable just before can influence what is sent. The earlier the value is set, the more samplers can use it, but variables set by one thread are never seen by another.
Choose clear names for variables, such as the purpose of the value, and use a short prefix for each area of the test. Dozens of variables with vague names make plans very hard to read.
CPre-Processors Compared with Config Elements
Config Elements set the stage once. Pre-Processors prepare each scene.
Config Elements supply defaults and data sources. Examples include HTTP Request Defaults, which gives every request the same server name, the CSV Data Set Config, which reads rows from a file, and the Counter, which counts upwards. They run before Pre-Processors in the order of execution, and they are often a simpler answer than a Pre-Processor.
| Question | Config Element | Pre-Processor |
|---|---|---|
| When does it run? | Before Pre-Processors for each sampler in scope | After Config Elements, before Timers and the sampler |
| Main job | Provide defaults and data | Prepare or modify the specific request |
| Typical example | Read the next row of a data file | Compute a value from several variables |
| Can it change the request itself? | Mostly by merging defaults | Yes, in many cases |
| Easier to read? | Usually yes | Depends on the element |
A theatre company sets the stage furniture before the show begins. Between scenes, a stagehand adjusts a few props. The furniture is the Config Element. The quick adjustments are the Pre-Processors.
A good rule of thumb
If the value comes from a file, a counter, or a random range, look for a Config Element first. If the value needs a decision, a calculation, a lookup, or a change to the request that is about to go, use a Pre-Processor. Using the simplest element that works keeps the plan lighter and easier to teach to new team members.
Plans that grow over years often end up with scripts doing jobs that a Config Element could do with no code. A short review of old scripts can remove surprising amounts of risk and maintenance.
CPre-Processors Compared with Timers and the Setup Thread Group
Three ways to do something before a request, each with a different meaning of “before”.
Beginners often reach for a Pre-Processor when another element would do better. Two close neighbours are the Timers and the Setup Thread Group.
Timers
A Timer adds a pause before its sampler runs. It does not change the request. Timers run after Pre-Processors, so the preparation is already finished by the time the pause begins. Use a Timer when the only thing you need before the request is to wait.
The Setup Thread Group
A Setup Thread Group is a special group that runs once, before the normal thread groups start. It is meant for one-time preparation, such as creating test accounts or clearing old data. A Pre-Processor, by contrast, runs again and again, before every sampler in its scope.
| Need | Best fit | Why |
|---|---|---|
| Different value for each user at each request | Pre-Processor | Runs per thread, per request |
| Create data once before the test begins | Setup Thread Group | Runs a single time before the main groups |
| Wait between requests | Timer | Designed for pauses |
| Same value shared by everybody | Property or Config Element | Computed once, read many times |
| Clean up after the test | Teardown Thread Group | Runs once after the main groups |
Before a football match, the groundskeeper marks the pitch once for everyone. Each player ties their own boots before kick-off. The Setup Thread Group is the groundskeeper. The Pre-Processors are the players tying their own laces.
Doing heavy one-time work in a Pre-Processor means repeating it for every request. If a task only needs to run once, move it to the Setup Thread Group.
TTwo Ends of a Request: Pre-Processors and Post-Processors
One prepares the request. The other studies the answer.
A Post-Processor runs after the sampler has received its response. It usually reads the response and captures values, such as a token or an identifier. The most famous Post-Processors are the extractors: the Regular Expression Extractor, the JSON Extractor, the CSS Selector Extractor, and the XPath Extractor. They capture values into variables.
A Pre-Processor and a Post-Processor often work as a pair. The Post-Processor of one step captures a value. The Pre-Processor of a later step may prepare it for use. Understanding this partnership clears up most of the confusion about the two types.
| Feature | Pre-Processor | Post-Processor |
|---|---|---|
| Runs | Before the sampler | After the response arrives |
| Looks at | The request about to be sent, and variables | The response that came back |
| Typical output | Prepared variables and modified requests | Captured variables |
| Typical example | User Parameters, JDBC PreProcessor | Regular Expression Extractor |
| Skipped when the sampler produces no result | No, it already ran | Yes, nothing to process |
A relay race has a runner who prepares the baton hand-off and a runner who receives it. One leg ends when the baton is passed, and the next leg begins with the received baton. The Post-Processor receives the value, and the Pre-Processor of the next step makes use of it.
When a value comes out of a response, think extractor. When a value must be prepared before sending, think Pre-Processor. When both are needed, use both, in that order.
TThread Safety and Per-User Data
Many users run at once, so shared values need special care.
JMeter runs each virtual user in its own thread, a separate line of work inside the program. Many threads run at the same moment. A property of thread safety means a piece of code behaves correctly even when many threads run it at the same time. Variables set by a Pre-Processor are private to one thread, so they are naturally safe. Problems appear when threads share something.
Where sharing creates trouble
Shared files
Two threads picking the same row from a data file may use the same account at the same time.
Shared properties
One thread changing a property can surprise another thread that is reading it.
Shared database rows
Two threads updating the same row can block or overwrite each other.
Shared counters in scripts
A global count updated by many threads can lose or duplicate numbers without protection.
Imagine a classroom where every pupil has their own notebook. Nobody interferes with anyone else. Now imagine one shared notebook on a single desk, where everybody scribbles at once. The writing becomes a mess. Variables are the private notebooks. Shared properties are the single desk.
Simple habits that keep things safe
- Prefer variables over properties for per-user data.
- Use built-in elements, such as the Counter, which are designed with threads in mind.
- Give each user separate data where possible, so threads never fight for the same row.
- If a script must share something, keep that part tiny and protect it with the language’s standard tools for safe sharing.
Thread safety bugs are among the hardest to find, because they appear only under real load and only sometimes. A plan that works perfectly with one user can behave oddly with two hundred.
HHow a Pre-Processor Works Internally
Follow one request from the moment it is chosen to the moment it leaves.
When a virtual user reaches a sampler in its journey, JMeter assembles all the elements in scope, sorts them by type, and runs them in the fixed order we met earlier. The steps below show what happens around the Pre-Processors.
sequenceDiagram
participant T as Virtual User Thread
participant C as Config Elements
participant P as Pre-Processors
participant M as Timers
participant S as Sampler
participant V as Server
T->>C: Apply defaults and data sources
C-->>T: Variables and defaults ready
T->>P: Run each Pre-Processor in scope
P-->>T: Variables set, request adjusted
T->>M: Apply timers
M-->>T: Pause completed
T->>S: Run the sampler
S->>V: Send the prepared request
V-->>S: Response
The thread reaches a sampler
Control moves to the next sampler in the journey, perhaps after a controller has decided it should run.
JMeter collects the elements in scope
It gathers every Config Element, Pre-Processor, Timer, Post-Processor, Assertion, and Listener that applies to this sampler.
Pre-Processors run in tree order
Among Pre-Processors, those that appear earlier in the tree run first. Their changes accumulate, so a later one can use what an earlier one set.
Variables are resolved
When the sampler runs, every variable reference in its settings is replaced with its present value.
The request leaves
The sampler sends the final, prepared request to the server and waits for the answer.
Think of a pilot’s pre-flight checklist. Items are completed in a set order, each building on the last, before the aircraft is allowed onto the runway. The sampler is the take-off, and the Pre-Processors are the checklist.
Because Pre-Processors of the same type run in tree order, you can arrange two of them so that the second uses the output of the first. Keep such dependencies obvious with clear names.
DData Flow and Lifecycle Across Iterations
A thread repeats its journey many times, and preparation repeats with it.
A thread group tells each virtual user how many times to repeat its journey. Each repetition is called an iteration. In each iteration, each sampler runs again, and so do the Pre-Processors in its scope. The values they set therefore change with every loop, unless the element is told to update only once.
The life of a variable across a test
| Moment | What happens to a prepared variable |
|---|---|
| Thread starts | The thread begins with its own empty set of variables |
| First iteration | Pre-Processors set values, and samplers use them |
| Next iteration | Values are set again, or kept if the element updates once per iteration |
| A later step needs an earlier value | The variable remains available until it is overwritten |
| Thread ends | The variables are discarded with the thread |
A waiter takes a fresh order pad to each table. At the end of the evening the pads are thrown away. Nothing from table one leaks onto table five, but the waiter can still refer to what was written earlier on the same table.
A stale value is a silent problem
Because a variable stays set until it is changed, a value from a previous iteration can accidentally be reused when the new preparation fails. The request then goes out with yesterday’s data, and nothing complains. Protect against this by clearing or resetting variables at the start of each iteration, where it matters, and by checking for the expected value in an assertion.
If a Pre-Processor fails silently, the sampler may still run using an older value. A test that looks healthy can be sending stale data. Assertions that check for the right response guard against this.
CCorrelation: When an Extractor Feeds a Pre-Processor
Correlation is the art of carrying a value from one response into the next request.
Modern web applications are full of values that change on every visit: session tokens, form tokens, order identifiers, and security codes. A test that replays a recorded request with an old value fails, because the server expects the fresh one. The technique of capturing the fresh value and sending it back is called correlation.
The usual partnership
Step one returns a value
The response contains a token or identifier that will be needed later.
A Post-Processor captures it
An extractor stores the value in a variable.
A Pre-Processor may reshape it
If the value must be modified, combined, or encoded, a Pre-Processor does that just before use.
The next sampler sends it
The request refers to the variable, and JMeter fills in the fresh value.
A hotel gives you a room key card at check-in. Each time you open your door, you must present that very card, not a copy from last year. Correlation is the habit of carrying today’s card to every door.
Many production test failures come from missed correlation: a token that was recorded once and replayed forever. Whenever a request works once but fails under load or on repeat, look for a value that should have been fresh.
CChoosing the Right Pre-Processor
A few questions lead you to the simplest tool that works.
flowchart TD
A["I need something prepared before a request"] --> B{"Is it a data file or counter?"}
B -- "Yes" --> C["Use a Config Element such as CSV Data Set Config"]
B -- "No" --> D{"Do users need different fixed values from a small table?"}
D -- "Yes" --> E["Use User Parameters"]
D -- "No" --> F{"Does the site put the session in the address?"}
F -- "Yes" --> G["Use HTTP URL Re-writing Modifier"]
F -- "No" --> H{"Is the value stored in a database?"}
H -- "Yes" --> I["Use JDBC PreProcessor, or fetch once in Setup Thread Group"]
H -- "No" --> J{"Must I limit how long a request may run?"}
J -- "Yes" --> K["Use Sample Timeout"]
J -- "No" --> L["Use JSR223 PreProcessor with a short script"]
Why this order of questions
The questions move from the simplest tool to the most flexible. Config Elements need no code. User Parameters need only a table. Special-purpose elements do one thing well. A script is last because it can do anything, and anything is also hard to read, test, and maintain.
When something is broken at home, you first try a screwdriver, then a wrench, and only after that do you call a builder with a van full of tools. Try the simple fix first.
Whenever you choose a script, write one sentence in the comments that says why no built-in element was suitable. The sentence helps the next reader judge whether the script is still needed.
CA Cookbook of Preparation Tasks
Common needs and the usual element that serves them.
| Task | Usual element | Notes |
|---|---|---|
| A different user name for each virtual user | CSV Data Set Config or User Parameters | Use a file for large numbers, a table for small sets |
| A fresh time stamp in each request | A built-in time function, or a short script | Functions are enough for simple needs |
| A random choice from a list | A random function or a short script | Keep the list small and clear |
| A unique reference number | Counter or a unique-identifier function | Check the format the system expects |
| Session identifier in the address | HTTP URL Re-writing Modifier | Only for sites that use it |
| A hidden form with many fields | RegEx User Parameters after an extractor | Test the extractor first |
| A value looked up from a database | JDBC PreProcessor | Prefer fetching once when possible |
| A computed signature or checksum | JSR223 PreProcessor | Use a well-known standard library |
| A limit on how long a request can run | Sample Timeout | Choose from real user tolerance |
| Clicking a random link on a page | HTML Link Parser | Not a realistic journey |
A recipe book lists which tool suits which job: a whisk for eggs, a knife for onions. A cookbook for tests does the same, and saves you from using the wrong tool out of habit.
JMeter also includes many built-in functions that can be written directly in a request, such as time, random, and unique-identifier functions. For simple needs, a function in the request field is lighter than any Pre-Processor at all.
TTime Stamps, Random Values, and Unique Identifiers
Three kinds of fresh values appear in almost every real test.
Time stamps
A time stamp is a number or text that records a moment. Many systems expect a current time in each request, either to reject old requests or to sign them. A prepared time stamp should be created just before sending, because a stamp prepared too early may expire by the time the request arrives. Time zones and formats matter, so check what the server expects.
Random values
A random value is chosen by chance within a range. Random choices make a test less repetitive: a random product, a random quantity, a random search word. Two cautions apply. Real traffic is rarely perfectly random, because popular items are chosen far more often than rare ones. And purely random choices can make results hard to reproduce, so many teams use a fixed starting value for repeatable runs.
Unique identifiers
A unique identifier is a value that should never repeat, such as an order number or a new account name. Many systems reject duplicates. Counters and standard unique-identifier functions are the safest sources. Hand-made values from random numbers can collide when thousands of threads run together.
Create it late
Prepare time stamps as close to sending as possible, so they stay fresh.
Mimic real habits
Weight the choices towards popular items if your real users behave that way.
Use proven sources
Rely on counters or unique-identifier functions instead of inventing your own scheme.
A time stamp is the date on a milk carton, which is useless if printed last month. A random value is picking a card from a deck. A unique identifier is a numbered raffle ticket, where two tickets with the same number would cause a quarrel.
Clocks differ between machines. If the system under test compares time stamps with its own clock, a load generator whose clock is minutes off can cause strange rejections that look like application bugs.
WWhat Happens When a Pre-Processor Fails
A quiet failure in preparation can produce loud, confusing errors later.
Preparation steps can fail. A script may hit an unexpected value. A database may be unreachable. A table may be missing a column. What JMeter does next depends on the element and on the kind of failure, but a general pattern is common: the problem is written to the log file, and the sampler may still run with whatever values happen to be available. Check the behaviour of your own version and elements, instead of assuming.
The chain of confusion
Preparation fails
The Pre-Processor cannot set the value it was meant to set.
The sampler still runs
It sends the request with an old value, an empty value, or the unreplaced variable name itself.
The server complains
It returns an error, a login page, or a message about missing data.
You look in the wrong place
The error appears on the sampler, so you suspect the server, though the cause lay one step earlier.
If a baker forgets to add yeast, the bread comes out flat, and the customer blames the oven. The real fault was in the preparation, long before the baking.
How to guard against it
- Add assertions that check for correct responses, so bad requests are marked as failures.
- Set a clear default for important variables, so a failed step produces an obvious value instead of a misleading blank.
- Read the log file after every run, and look for errors from the elements you added.
- In scripts, check for missing data and write a short log line that names the step.
When a request contains the literal text of a variable name, including the dollar sign and brackets, it means the variable was never set. This is one of the quickest signs that a preparation step did not run or failed.
DDebugging Pre-Processors
You cannot see preparation directly, so you need windows into it.
A Pre-Processor does not appear in the results, so debugging means looking at what it did: which variables it set, what the request looked like when it left, and what the log says. JMeter offers several friendly tools for this.
View Results Tree
Shows the exact request each sampler sent, so you can check whether prepared values arrived.
Debug Sampler
Produces a result listing the current variables, properties, and system values at that point in the journey.
Debug PostProcessor
Adds variable and property details to the result of a sampler, useful right after a step you want to inspect.
The log file
Records errors and any messages written by your scripts. Always read it after a failed run.
A calm routine
Run with one user
Remove the noise of many threads. Use a single user and a single loop.
Look at the sent request
In View Results Tree, open the request tab and compare the real values with what you expected.
Inspect the variables
Insert a Debug Sampler just before the suspect step and read the variable list.
Read the log
Look for error lines from the element you are checking.
Scale up slowly
Add a few users, then more, to find problems that appear only with sharing.
A plumber who cannot see inside the wall listens at the pipe, checks the meter, and looks at the tap. Debugging preparation is the same: you inspect what comes out and what was recorded, because you cannot watch the inside directly.
Remove or disable debug elements before a real test. They create results of their own and add cost, so they belong to the building stage only.
PPerformance Cost of Preparation
Every preparation step uses the same machine that is generating your load.
The load generator has a limited amount of processor power. Time spent preparing a request is time not spent sending or receiving. For a few users this is invisible. When thousands of threads run, small costs multiply, and a slow Pre-Processor can reduce the load you can generate or distort the measurements.
Where the costs hide
| Source of cost | Why it matters | Remedy |
|---|---|---|
| Scripts compiled on every run | Compiling is slow and repeats for every request | Use JSR223 with the compiled-script cache enabled |
| Older script engines | BeanShell is generally slower than JSR223 | Move new and busy scripts to JSR223 with Groovy |
| Database calls per request | Adds network time and database load | Fetch data in advance when possible |
| Wide scope | The element runs before every sampler in reach | Narrow the scope to the samplers that need it |
| Heavy work in scripts | Large loops or string building burn processor time | Keep scripts small and prepare data ahead of time |
| Excessive logging | Writing many lines per request slows the generator | Log only warnings and errors in real runs |
A taxi driver who stops to fill in a form before every passenger gets fewer fares per hour. Preparing a request is the form. A short form is fine. A long form on every trip loses money.
Measuring the cost
The simplest check is to run the same test with and without the Pre-Processor, for the same number of users, and compare throughput and processor use on the generator. If throughput drops or processor use climbs sharply, the preparation is expensive. Run such comparisons in a quiet environment and repeat them, because single runs can mislead.
A useful rule of thumb is that the load generator should have spare capacity. If it runs near its limit, you are measuring your generator as much as your system.
SScalability and Distributed Testing
When one machine is not enough, preparation must work on many machines at once.
A single JMeter machine has limits. To generate more load, teams use distributed testing, in which a controller directs several other machines, called remote engines or workers. Each worker runs its own copy of the test plan. This has important consequences for preparation.
Things that change when you distribute
Data files are per machine
Each worker reads its own copy of a data file, so the same row can be used on several machines unless you split the file.
Variables stay local
A variable set on one worker is invisible to the others, which is usually what you want.
Properties need care
Properties belong to one worker’s program. Setting one on a worker does not change the others.
Counters repeat
Each worker counts on its own, so two machines can produce the same number unless you give them different starting points.
Imagine ten branches of a bank, each with its own numbered ticket machine. Without coordination, branch three and branch seven will both call out “ticket 42”. If the numbers matter across branches, each branch needs its own range.
Habits that scale
- Split data files so each worker receives different rows.
- Give each worker its own numeric range for counters and unique identifiers.
- Pass settings to each worker through properties set when it starts.
- Keep preparation cheap so each worker can spend its power sending requests.
- Check each worker with a tiny run before the real test.
Duplicate accounts are the classic distributed testing surprise. If two workers log in as the same user at the same time, the system may log one out, and you will chase a problem that your own setup created.
LLarge Data Sets and Memory
Preparation data that is too big for memory causes slow tests and strange failures.
Some tests need thousands or millions of distinct values: accounts, products, search words. A few ways of holding that data are cheap, and others are very expensive. The choice affects how much memory the load generator needs.
| Approach | Memory behaviour | Good for |
|---|---|---|
| CSV Data Set Config reading a file | Reads rows as needed, light on memory | Large lists of accounts or values |
| User Parameters table | Stored in the plan, grows with every column | A handful of users |
| Script that loads a whole file into memory | Holds all values for every thread, or one copy at best | Small lists only |
| Database query per request | Light on the generator, heavier on the database | Data that changes constantly |
A librarian can carry a single book to a reader, or wheel the entire library into the reading room. A file read on demand is the single book. Loading everything into memory is the whole library on a trolley.
Habits that save memory
- Keep large lists in files and read them with the data file element.
- Avoid storing large values, such as whole responses, in variables unless needed.
- Release or overwrite large variables when they are no longer useful.
- Give the JMeter program enough memory, and watch it during the run.
An out-of-memory failure in the middle of a long test wastes hours. Run a short rehearsal at full user count first, and watch memory, before committing to the long run.
MMonitoring, Logging, and Metrics
Preparation leaves no rows in the results, so you must watch it another way.
Because Pre-Processors do not produce results, a healthy-looking report can hide preparation problems. The solution is to observe preparation through logs, through the requests that came out, and through the health of the load generator.
flowchart LR
PP["Pre-Processors"] --> RQ["Prepared request"]
PP --> LG["JMeter log file: warnings and errors"]
RQ --> SV["System under test"]
SV --> RS["Results file"]
RS --> RP["Report: errors, percentiles, throughput"]
GH["Generator health: CPU, memory, network"] --> DB["Dashboard"]
LG --> DB
RP --> DB
What to watch
- The log file: errors from scripts, database calls, and missing variables.
- The error rate: sudden jumps often mean prepared values went bad.
- Request details for a sample: a few recorded requests, to confirm the values look right.
- Generator health: processor, memory, and network, to see whether preparation is costly.
- Database load: if a database Pre-Processor is used, check its effect on the database.
A restaurant manager cannot taste every dish, but can read the order tickets, listen for complaints, and check that the kitchen is not overheating. Each is an indirect view of the preparation.
Mark in your records when each run started and stopped, and which version of the plan was used. When something looks odd later, those notes let you compare against a known good run.
SSecurity Considerations
Preparation often touches credentials, databases, and scripts, so it deserves extra care.
Pre-Processors handle some of the most sensitive material in a test: user names, passwords, tokens, connection details, and scripts that can do almost anything. A test plan can be shared, stored, and copied, so secrets inside it travel with it.
Before the test
Use test accounts and test data, never real customers. Keep passwords and connection details out of the plan text where possible, and supply them through protected settings at run time. Make sure you have permission to test the target.
During the test
Limit what scripts can reach. Avoid logging passwords or tokens, because log files are widely readable. Point database elements only at test databases.
After the test
Remove test accounts and data that were created, secure or delete result and log files, and review the plan for leftover secrets before sharing it.
Specific risks
- Scripts run with the power of the JMeter program. A plan from an unknown source may contain scripts that read files or call other systems, so review before you run it.
- Database Pre-Processors can change real data if pointed at the wrong server, so double-check connection details.
- Tokens and passwords in plans can leak through shared files, screenshots, and version control history.
- Load can look like an attack. Always notify the owners of the system and test only what you are allowed to test.
A set of keys left in a shared drawer can open every door in the building. Credentials in a test plan are keys in a drawer. Keep the drawer locked, and hand out only the keys that are needed.
Never run a test plan received from an unknown source without reading its scripts first. A script element is code that executes on your machine.
AAdvantages, Disadvantages, and Trade-offs
Preparation makes tests realistic, and it costs effort and complexity.
Advantages
- Makes each virtual user behave like a distinct person
- Keeps tokens, sessions, and identifiers fresh
- Prepares requests close to the moment they are sent
- Scope controls let you target exactly the samplers that need it
- A wide choice of elements, from no-code tables to full scripts
- Works naturally with extractors for correlation
Disadvantages
- Invisible in the results, so failures are easy to miss
- Runs again for every sampler in scope, so cost multiplies
- Scripts can become hard to read and maintain
- Shared data and properties create thread safety risks
- Database elements can load the very systems under test
- Order of execution surprises beginners
| Trade-off | What you gain | What you give up |
|---|---|---|
| Script instead of a built-in element | Total flexibility | Readability and speed of maintenance |
| Per-request preparation | Fresh values every time | Processor time on the generator |
| Preparing in advance, in a setup stage | Low cost during the test | Values may be stale or limited |
| Wide scope | Fewer elements to maintain | Unnecessary work on samplers that do not need it |
| Random values | Variety and less caching | Harder to reproduce a run exactly |
Preparing a meal fresh to order tastes best but needs more hands in the kitchen. Preparing everything in advance is faster at serving time but the food may sit too long. Each choice buys something and costs something.
The best plans prepare as little as realism requires. Every extra step is something that can fail, slow down, or confuse the next reader.
PDesign Patterns for Preparation
Good habits repeat across good test plans.
Prepare as close as possible
Place each Pre-Processor as near as possible to the samplers that use it, so scope stays small and the plan stays readable.
Simple first
Prefer Config Elements, functions, and tables over scripts. Move to a script only when nothing simpler fits.
Fetch once, reuse many
If data does not change per request, read it in a setup stage or from a file, instead of querying it before every sampler.
Verify what you prepared
Pair every critical preparation with an assertion on the response, so a failed step shows up as a failure.
Name by purpose
Give each element a name that says what it prepares, such as “Set session token for checkout”.
One job per element
Keep each Pre-Processor focused on a single task, so problems are easy to locate.
A pattern called “Prepare, Send, Capture, Check”
Prepare
A Pre-Processor or Config Element makes the request ready.
Send
The sampler sends it to the server.
Capture
A Post-Processor stores any values needed later.
Check
An assertion confirms the response was correct.
A good mail clerk prepares the envelope, posts it, files the receipt, and confirms delivery. Doing all four steps, in order, is what makes the whole job dependable.
AAnti-patterns to Avoid
Some habits look clever and cause trouble later.
The pattern
Putting a heavy Pre-Processor, such as a database lookup, directly under the thread group.
Why it hurts
It runs before every sampler in the group, multiplying database load and slowing the generator.
Better approach
Narrow the scope to the one sampler that needs it, or fetch the data once in a setup stage.
The pattern
A single giant script that prepares dozens of values and changes many things at once.
Why it hurts
Nobody else can read it, test it, or safely change it, and one bug breaks everything.
Better approach
Split the work into small, named elements, each with a single clear purpose.
The pattern
Using shared properties to hold per-user data.
Why it hurts
Threads overwrite each other, so users receive each other’s values and the test becomes unreliable.
Better approach
Use variables, which are private to each thread.
The pattern
Never checking whether preparation succeeded.
Why it hurts
Requests go out with stale or blank values, and the resulting errors look like server faults.
Better approach
Add assertions, set safe defaults, and read the log after every run.
The pattern
Hard-coding passwords and tokens in scripts and shared plans.
Why it hurts
Secrets leak through files, screenshots, and history.
Better approach
Supply secrets at run time through protected settings, and use test accounts only.
OOrganising and Maintaining Preparation Elements
A plan that is easy to read stays correct for longer.
Test plans live for years. People join and leave the team, the application changes, and the plan is edited many times. Preparation elements are scattered through the tree and invisible in the results, so they are easy to forget. A little organisation prevents big confusion later.
Habits that help
- Name every element for its purpose. Avoid default names such as “JSR223 PreProcessor”, which tell the reader nothing.
- Add comments. Every element has a comments field. Use it for the reason the element exists and the version of the system it was written for.
- Group related steps under controllers. Putting the preparation near its samplers makes the story of each step easy to follow.
- Keep scripts in files for reuse. A shared script file avoids copies that drift apart over time.
- Store plans in version control. A history of changes explains why a plan is the way it is.
- Review old plans regularly. Remove elements that no longer serve a purpose.
A kitchen with labelled jars and neatly placed tools lets a new cook get started at once. A kitchen with unlabelled jars makes every task a guessing game. Names and comments are the labels.
Ask a colleague to read your plan without your help. Wherever they get confused is where a name or a comment is missing.
PProving Your Preparation Works
Preparation is invisible, so you must test it on purpose.
A Pre-Processor that silently does nothing looks exactly like one that works. The only way to know is to check the evidence: the request that was sent, the values that were set, and the responses that came back. A short routine gives you that confidence before you scale up.
Run one user, one loop
Open the sent request in the results tree and compare each prepared value with what you intended.
Run a few users
Check that different users received different values, where they should, and the same values where they should not differ.
Run several loops
Confirm values refresh at each iteration, and that nothing from the previous loop leaks into the next one.
Break something on purpose
Remove a data row, change a name, or stop a database in a test environment. Confirm the failure is visible in the log or in an assertion.
Rehearse at full size
Run briefly with the full user count and watch memory, processor use, and errors.
| Experiment | What you should see | If you do not |
|---|---|---|
| Two users, two data rows | Different values in each user’s requests | Both users share a row, or the scope is wrong |
| Three loops of one user | A fresh value in each loop | The element is set to update only once, or an old value is reused |
| Remove the needed data | A clear error in the log or a failed assertion | Failure is silent, so add checks |
| Rename the variable in the request | The literal variable name appears in the sent request | The request does not use the variable at all |
A fire alarm must be tested by pressing the test button. An alarm that has never been tested is only a hope. A preparation step that has never been seen to fail is the same.
Repeat the routine whenever the application, the plan, or the data files change. A small rehearsal costs minutes and can save a whole night’s run.
TTroubleshooting a Pre-Processor That Misbehaves
Most problems come from a small set of causes. Match your symptom with the table.
| Symptom | Likely cause | What to check |
|---|---|---|
| The request shows the literal variable name | The variable was never set, or set after the sampler ran | The scope, the order of elements, and the log for errors |
| All users send the same value | One shared column, a shared property, or the same data row | Data element settings, sharing mode, and variable use |
| The value never changes between loops | Update-once setting, or a variable that was not reset | The loop settings of the element |
| Pre-Processor seems not to run | It sits where no sampler is in scope | Its parent in the tree and the enabled state |
| Wrong order of preparation | Two elements depend on each other but run in the wrong order | Their order in the tree among elements of the same type |
| Config value is not changed as expected | Config Elements run before Pre-Processors | Move the change earlier, or use a different element |
| Test is slower than expected | Heavy script, wide scope, or database call per request | Cost of each element and the generator’s processor use |
| Session identifier missing in addresses | Wrong argument name, or the site uses cookies instead | How the application tracks sessions |
| Database element fails | Wrong pool name, missing connection element, or wrong query type | The connection configuration and the log |
| Script errors on only some requests | Unexpected or missing values for certain users | The data and the log lines for those users |
A method for any puzzle
Reproduce it small
Use one user and one loop. If the fault disappears, the cause involves sharing.
See the sent request
Compare what was sent with what you expected, field by field.
Check the order and the scope
Confirm the element is in scope and runs where you think it does.
Read the log
Look for errors from the element in question.
When the sent request is wrong, look at preparation. When the sent request is right but the response is wrong, look at the server. Making that first split saves hours.
AA Worked Example: Signing In and Placing an Order
Follow an imaginary online shop test from sign-in to order.
A team wants to test a shop where many different customers sign in, add an item, and place an order. Each customer needs a distinct account, and each order needs a unique reference. The shop returns a token after sign-in that every later request must carry.
flowchart TD
D["Data file: one account per user"] --> L["Sampler: Sign In"]
L --> X["Post-Processor: capture token"]
X --> P1["Pre-Processor: build unique order reference"]
P1 --> O["Sampler: Place Order with token and reference"]
O --> A["Assertion: order confirmation text present"]
A --> R["Results and report"]
P1 --> LG["Log shows any preparation errors"]
Distinct accounts
A data element reads one account for each virtual user from a file, so no two simultaneous users share a sign-in.
Sign in and capture
The sign-in request goes out. An extractor captures the token from the response into a variable.
Prepare the order reference
Just before the order request, a short, clearly named Pre-Processor builds a unique reference from the user’s identity and a counter, so no two orders collide.
Send and check
The order request carries the token and the reference. An assertion confirms the confirmation message appears.
Watch and review
After the run, the team checks the log for preparation errors and the report for failures.
What makes this plan healthy
- The Pre-Processor has a narrow scope, attached only to the order step.
- It has one job, and a name that says what it does.
- Its result is verified by an assertion on the response.
- Values come from proven sources: a data file for accounts and a counter for uniqueness.
This example is imaginary and simplified. Real shops add many more steps, but the habit of preparing narrowly, capturing carefully, and checking every critical response is the same.
CCommon Misunderstandings
Six ideas that beginners often get wrong.
“Order in the tree is order of execution”
Elements run by type first, then by tree order within the same type. A Pre-Processor always runs before its sampler.
“A Pre-Processor runs once”
It runs before every sampler in its scope, every iteration. One element can run thousands of times.
“It appears in the results”
It produces no result row, so problems with it are invisible unless you look at the requests and the log.
“Variables are shared by all users”
Variables are private to each thread. Only properties are shared across the whole program.
“A script is always the best answer”
A script is the most flexible tool and the hardest to maintain. Start with simpler elements.
“If it works for one user it works for all”
Sharing, memory, and timing problems appear only with many users running together.
A recipe that works in a small home kitchen may fail in a restaurant, because the stove, the timing, and the helpers all change. A test that works for one user is the home kitchen. A test with a thousand is the restaurant.
A habit that corrects all six
Before you rely on a preparation step, ask three questions. What exactly will it set, and for whom? When will it run, and how often? How will I see that it worked? Honest answers to those three questions expose most misunderstandings before they cost you a run.
Do not trust a green report alone. Preparation faults often produce quick error pages that look fine in a speed chart. Always pair speed with correctness checks.
BBest Practices and Common Mistakes
A short checklist to carry into your next test.
Choose the simplest element
Prefer Config Elements, functions, and no-code tables, and use scripts last.
Keep scope narrow
Attach each Pre-Processor to the smallest group of samplers that need it.
Use JSR223 with Groovy for scripts
Enable compiled-script caching, keep scripts short, and avoid older engines for new work.
Prefer variables to properties
Keep per-user data in variables so threads cannot trample each other.
Verify with assertions
Check each critical response so failed preparation shows up as a failure.
Read the log after every run
Many preparation faults appear only there.
Name, comment, and version
Explain each element’s purpose, and store plans in version control.
Protect secrets
Use test accounts, and keep passwords and tokens out of shared files and logs.
Common mistakes in one list
- Using a heavy Pre-Processor with a wide scope, so it runs far too often
- Writing long scripts that only one person understands
- Holding per-user data in shared properties
- Forgetting that Config Elements run before Pre-Processors
- Never checking that preparation succeeded
- Leaving old BeanShell scripts in busy parts of the plan without review
- Splitting data badly across distributed workers, so users collide
- Hard-coding passwords and tokens in shared plans
- Leaving debug elements enabled during a real run
RReal-World Scenarios
Five typical situations, described in general terms so you can adapt them.
The cached shortcut
A media site tests its search page with a single fixed search word. The results come back astonishingly fast, because the server caches the answer. After adding a preparation step that picks a different word from a list for every request, the cache stops helping, and the true cost of searching appears. The first test had been measuring the cache, not the search.
The expired token
A banking-style application issues a security token valid for a few minutes. A recorded test replays the token from the recording, and nearly every request after the first is rejected. By capturing a fresh token after each sign-in and preparing it for later requests, the test finally exercises the real journey.
The duplicate account storm
A team distributes a test over four machines, each reading the same data file. Several workers sign in as the same user at once, and the system logs them out. After splitting the file so each worker gets different accounts, the strange logout errors disappear.
The slow script
An old plan uses a long BeanShell script before every request to compute a signature. At high load, the generator’s processor reaches its limit, and throughput stalls even though the server is idle. Moving the logic to a short, cached JSR223 script restores the generator’s speed and exposes the server’s real limits.
The hanging request
A legacy service occasionally never answers. Virtual users wait forever, and the test seems stuck. Adding a time limit to the affected sampler turns each hang into a recorded failure after a fixed time, so the test keeps flowing and the problem becomes visible in the error rate.
QQuick Reference
A one-page summary you can keep next to your test plan.
| Topic | Summary |
|---|---|
| What it is | An element that prepares a request just before the sampler runs |
| Order of execution | Config Elements, Pre-Processors, Timers, Sampler, Post-Processors, Assertions, Listeners |
| Scope | Set by the parent in the tree: one sampler, a controller, a group, or the whole plan |
| Different values per user | User Parameters for small sets, a data file element for large sets |
| Session in the address | HTTP URL Re-writing Modifier |
| Values from a database | JDBC PreProcessor, or fetch once in a setup stage |
| Custom logic | JSR223 PreProcessor with Groovy, compiled script cache on |
| Limit on request time | Sample Timeout |
| Where results appear | Nowhere: check the sent request and the log |
| Per-user data | Variables, not properties |
| Distributed tests | Split data files, give workers separate ranges, keep preparation cheap |
| Security | Test accounts, protected secrets, reviewed scripts |
Five questions before pressing start
- Does every virtual user get the values it needs, and are they different where they should be?
- Is each Pre-Processor attached to the smallest scope that works?
- Have I seen the sent request and confirmed the prepared values arrived?
- Will a failed preparation show up as a failure, through assertions or the log?
- Are secrets protected, and are debug elements switched off?
FFrequently Asked Questions
Quick answers to the questions beginners ask most often.
SSummary and Key Takeaways
Pre-Processors are the dressing room of JMeter requests. They run just before a sampler, after Config Elements and before Timers, and they turn identical robot requests into realistic traffic by giving each virtual user its own values, tokens, and limits. Used well, they are small, narrow, named, and verified. Used badly, they hide failures, waste processor time, and confuse the next reader. If you remember one idea, let it be this: prepare only what realism requires, as close to the request as possible, and always check that the preparation really worked.
Key Takeaways
- A Pre-Processor prepares a request just before it is sent. It runs after Config Elements and before Timers, the sampler, and Post-Processors.
- Scope sets how often it runs. It runs before every sampler under its parent, in every iteration, so narrow scope saves work.
- Pick the simplest element. Use Config Elements, tables, and functions first, and a short JSR223 script only when nothing simpler fits.
- Use variables for per-user data. Variables are private to a thread, while properties are shared by everyone and need care.
- Preparation is invisible in the results. Check the sent request, add assertions, and read the log after every run.
- Plan for scale. Keep preparation cheap, split data across workers in distributed tests, and watch the generator’s memory and processor use.
- Protect the data and the plan. Use test accounts, keep secrets out of shared files, and review scripts before running them.