如何在单测试迭代中从CSV获取多值并动态生成可变元素XML/JSON
Hey Bernie, let's break down what's happening here and fix it step by step.
核心问题根源
The issue you're hitting is how JMeter's CSV Data Config works by default: it only loads one row of CSV data per test iteration. That means once an iteration starts, the ${csvBook} variable gets locked to that single row's value—no matter how many times you call vars.get("csvBook") inside a loop during that iteration, it'll keep returning the same value.
Luckily, there are two solid approaches to solve both your needs: grabbing multiple CSV values in one iteration, and dynamically building XML/JSON with a variable number of elements.
方法1:在JSR223 Sampler(推荐用Groovy)中直接读取整个CSV
This is the most flexible approach, especially if you need full control over how many rows you pull or how you structure your output. Groovy is preferred over BeanShell here because it's faster and has cleaner syntax for data manipulation.
Here's a ready-to-use script:
// Replace this with your CSV file path (relative to JMeter's bin folder, or absolute path) def csvFilePath = "./your-books-data.csv" def bookList = [] // Read the CSV, skip the header row (remove the 'if (index > 1)' check if no header) new File(csvFilePath).eachLine { line, index -> if (index > 1) { // If your CSV has multiple columns (e.g., "bookTitle,author,price"), split like this: // def columns = line.split(",") // bookList.add(columns[0].trim()) // grab just the title bookList.add(line.trim()) // use this if each row is a single book value } } // -------------------------- // Option 1: Build dynamic JSON // -------------------------- def jsonBuilder = new groovy.json.JsonBuilder() jsonBuilder { books bookList } vars.put("dynamicBooksJson", jsonBuilder.toString()) // -------------------------- // Option 2: Build dynamic XML // -------------------------- def xmlWriter = new StringWriter() def xmlBuilder = new groovy.xml.MarkupBuilder(xmlWriter) xmlBuilder.books { bookList.each { book -> book(book) } } vars.put("dynamicBooksXml", xmlWriter.toString())
How to use this:
- Add a JSR223 Sampler to your test plan (replace the BeanShell Sampler you were using)
- Paste this script, update the
csvFilePathto match your file - Adjust the CSV parsing logic if your file has multiple columns
- The generated JSON/XML will be stored in
${dynamicBooksJson}and${dynamicBooksXml}variables, which you can use in subsequent samplers (like HTTP Request bodies)
方法2:结合CSV Data Config + 循环控制器 + 计数器
If you prefer to stick with the CSV Data Config, you can tweak its settings to pull multiple rows in one iteration:
- Configure CSV Data Config:
- Set
Recycle on EOFtoFalse - Set
Stop thread on EOFtoFalse
- Set
- Add a Loop Controller:
- Set the loop count to the number of CSV rows you want to fetch in one iteration
- Add a Counter inside the Loop Controller:
- Start:
1 - Increment:
1 - Reference Name:
rowNumber
- Start:
- Add a JSR223 Sampler inside the Loop Controller to fetch the specific row:
// Get the full CSV dataset from JMeter's internal storage def csvDataset = vars.getObject("csvData") // Fetch the row matching our counter (adjust index if your CSV has a header) def currentBook = csvDataset.get(${rowNumber}).get("csvBook") // Build your XML/JSON incrementally (use vars.put to append to a string variable) def existingXml = vars.get("partialBooksXml") ?: "<books>" existingXml += "<book>${currentBook}</book>" vars.put("partialBooksXml", existingXml) - After the Loop Controller, add another JSR223 Sampler to finalize the XML/JSON:
def finalXml = vars.get("partialBooksXml") + "</books>" vars.put("dynamicBooksXml", finalXml) // Clear the partial variable for the next iteration vars.remove("partialBooksXml")
Key Notes:
- This method works best if you know exactly how many rows you need per iteration
- The
csvDataobject is JMeter's internal storage for the full CSV dataset—this only works if your CSV Data Config is set to load all rows upfront
Why your original BeanShell approach didn't work
As mentioned earlier, CSV Data Config assigns variables once per iteration. So when you loop inside a BeanShell Sampler during that iteration, vars.get("csvBook") will always return the first (and only) row loaded for that iteration. The above methods bypass this limitation by either reading the full CSV directly or accessing the raw dataset to pull specific rows.
内容的提问来源于stack exchange,提问作者Bernie Wong

