Custom Feeders
Overview
Custom feeders generate unlimited, realistic data on-the-fly without pre-built CSV files.
Use cases: - Generate unique email addresses - Generate valid credit card numbers - Generate realistic timestamps - Generate data with constraints (age >18, balance >0) - Generate data that changes over time
CSV Feeders vs Custom Feeders
CSV Feeder (Limited)
csv("data/users.csv")
// ✓ Simple
// ✓ Easy to set up
// ✗ Limited to rows in file
// ✗ Can't generate unlimited data
// ✗ Can't apply logic/constraints
Custom Feeder (Flexible)
Iterator<Map<String, Object>> feeder = Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
map.put("email", "user" + UUID.randomUUID() + "@example.com");
return map;
}).iterator();
// ✓ Generate unlimited unique data
// ✓ Apply logic and constraints
// ✓ Generate realistic patterns
// ✓ No file required
Basic Custom Feeder
Template
Iterator<Map<String, Object>> customFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
// Generate field 1
map.put("fieldName1", generateValue1());
// Generate field 2
map.put("fieldName2", generateValue2());
return map;
}).iterator();
// Use in scenario
.feed(new SequenceFeeder(customFeeder))
.exec(http("Request")
.get("/endpoint?field1=#{fieldName1}&field2=#{fieldName2}")
)
Example 1: Email Generator
Code
Iterator<Map<String, Object>> emailFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
int randomNum = new Random().nextInt(100000);
map.put("email", "user" + randomNum + "@example.com");
return map;
}).iterator();
// Use
.feed(new SequenceFeeder(emailFeeder))
.exec(http("Register")
.post("/register?email=#{email}")
)
Result
First iteration: email=user42156@example.com
Second iteration: email=user87234@example.com
Third iteration: email=user12389@example.com
(unique every time)
Example 2: Credit Card Generator
Code
Iterator<Map<String, Object>> creditCardFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
Random random = new Random();
// Visa prefix: 4532 (valid test number)
String cardNum = "4532" + String.format("%012d", random.nextLong() % 1000000000000L);
map.put("cardNumber", cardNum);
map.put("expiry", "12/25");
map.put("cvv", String.format("%03d", random.nextInt(1000)));
return map;
}).iterator();
// Use
.feed(new SequenceFeeder(creditCardFeeder))
.exec(http("Payment")
.post("/payment")
.body(StringBody("{\"cardNumber\": \"#{cardNumber}\", \"cvv\": \"#{cvv}\"}"))
)
Example 3: Timestamp Generator
Code
Iterator<Map<String, Object>> timestampFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
// Current time + random offset (last 7 days)
long now = System.currentTimeMillis();
long sevenDaysMs = 7 * 24 * 60 * 60 * 1000L;
long randomOffset = new Random().nextLong() % sevenDaysMs;
long timestamp = now - randomOffset;
map.put("timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
.format(new Date(timestamp)));
return map;
}).iterator();
// Use
.feed(new SequenceFeeder(timestampFeeder))
.exec(http("Create Event")
.post("/events")
.body(StringBody("{\"timestamp\": \"#{timestamp}\"}"))
)
Example 4: Constrained Data (Age >18)
Code
Iterator<Map<String, Object>> personFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
Random random = new Random();
// Generate age between 18 and 80
int age = 18 + random.nextInt(62);
// Generate name
String[] names = {"Alice", "Bob", "Charlie", "Diana", "Eve"};
String name = names[random.nextInt(names.length)];
map.put("age", age);
map.put("name", name);
return map;
}).iterator();
// Constraint: Only use if age >= 18
.feed(new SequenceFeeder(personFeeder))
.doIf(session -> Integer.parseInt(session.getString("age")) >= 18)
.then(
http("Register Adult")
.post("/register?name=#{name}&age=#{age}")
)
Example 5: Realistic Product Names
Code
Iterator<Map<String, Object>> productFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
Random random = new Random();
String[] adjectives = {"Premium", "Ultra", "Deluxe", "Professional", "Standard"};
String[] nouns = {"Widget", "Gadget", "Tool", "Utility", "Device"};
String[] categories = {"Pro", "Plus", "Max", "Basic", "Essential"};
String productName = adjectives[random.nextInt(adjectives.length)] + " " +
nouns[random.nextInt(nouns.length)] + " " +
categories[random.nextInt(categories.length)];
double price = 10 + random.nextDouble() * 1000; // $10-$1010
map.put("productName", productName);
map.put("price", String.format("%.2f", price));
return map;
}).iterator();
Performance Considerations
Good Feeder (Efficient)
Iterator<Map<String, Object>> efficientFeeder =
Stream.generate(() -> {
Map<String, Object> map = new HashMap<>();
map.put("id", UUID.randomUUID().toString()); // Fast
return map;
}).iterator();
Bad Feeder (Inefficient)
Iterator<Map<String, Object>> inefficientFeeder =
Stream.generate(() -> {
// ❌ Creating new objects every iteration
// ❌ Complex logic
// ❌ Database calls
Map<String, Object> map = new HashMap<>();
// This would slow down the load test
User user = database.getRandomUser(); // SLOW!
map.put("userId", user.getId());
return map;
}).iterator();
Key Takeaways
- Custom feeders generate unlimited data
- No file storage needed
- Apply logic and constraints
- Stream.generate() creates infinite iterator
- Keep feeder logic efficient (fast)
- Realistic data = realistic load test
Navigation
← Previous: Load Test Analysis
→ Next: Advanced Patterns
↑ Up: Documentation Index