We covered correlation in depth in Chapter 5, but now let us apply it to our specific Shopping Portal test plan. This is where theory meets practice. Our shopping flow has three critical correlation points -- values that are generated dynamically and must be captured and reused.
| Step | Value to Extract | Where It Comes From | Where It Is Used |
|---|---|---|---|
| Login | authToken | POST /api/auth/login response body: $.token | Authorization header for all subsequent requests |
| Search | productId | GET /api/products?q=... response body: $.products[0].id | Product detail URL, Add to Cart body |
| Checkout | orderId | POST /api/checkout response body: $.orderId | Order confirmation URL: GET /api/orders/${orderId} |
After the login request succeeds, the server returns a JSON response with an authentication token. We need to capture this and send it in the Authorization header for every subsequent request.
<!-- Add as a child of the POST Login sampler -->
<JSONPostProcessor guiclass="JSONPostProcessorGui"
testclass="JSONPostProcessor"
testname="Extract Auth Token">
<stringProp name="JSONPostProcessor.referenceNames">
authToken
</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">
$.token
</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">TOKEN_NOT_FOUND</stringProp>
</JSONPostProcessor>
<!-- Then add an HTTP Header Manager AFTER login
to include the token in all subsequent requests -->
<HeaderManager guiclass="HeaderPanel"
testclass="HeaderManager"
testname="Auth Header">
<collectionProp name="HeaderManager.headers">
<elementProp name="Authorization" elementType="Header">
<stringProp name="Header.name">Authorization</stringProp>
<stringProp name="Header.value">Bearer ${authToken}</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>The search API returns a list of products. We need to grab the first product's ID so we can view its detail page and add it to the cart. This is the classic "response -> next request" correlation pattern.
<!-- Add as a child of the GET Search sampler -->
<JSONPostProcessor guiclass="JSONPostProcessorGui"
testclass="JSONPostProcessor"
testname="Extract Product ID">
<stringProp name="JSONPostProcessor.referenceNames">
productId
</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">
$.products[0].id
</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">PRODUCT_NOT_FOUND</stringProp>
</JSONPostProcessor><!-- Add as a child of the POST Checkout sampler -->
<JSONPostProcessor guiclass="JSONPostProcessorGui"
testclass="JSONPostProcessor"
testname="Extract Order ID">
<stringProp name="JSONPostProcessor.referenceNames">
orderId
</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">
$.orderId
</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">ORDER_NOT_FOUND</stringProp>
</JSONPostProcessor>Correlation is where most test plans break. When something goes wrong, here is a systematic debugging approach:
Add a View Results Tree listener (GUI mode only, never in actual load test)
Run with 1 thread, 1 loop -- isolate the correlation issue from concurrency
Click the failing request in View Results Tree and check the request tab -- is the variable showing ${productId} literally or the actual value?
If it shows ${productId} literally, the extractor did not find a match -- check the PREVIOUS response body
Click the previous response and verify the JSON path manually -- is the structure $.products[0].id or $.data.products[0].id?
Check the default value -- if it shows "PRODUCT_NOT_FOUND", the extractor ran but found nothing
Add a Debug Sampler after the extractor to see all JMeter variables and their current values
Once fixed, REMOVE View Results Tree and Debug Sampler before load testing
Never leave View Results Tree or Debug Sampler enabled during a real load test. They consume enormous amounts of memory because they store every single response. A 100-user test with these listeners enabled will crash your JMeter instance within minutes.
Key Point: Our shopping flow needs three correlation points: auth token from login, product ID from search, and order ID from checkout. Always set meaningful default values so failed extractions are immediately obvious.
Key Point: Identify every dynamic value in your flow, add JSON/Regex extractors with meaningful defaults, and always debug with 1 thread first before scaling up.