When parameterizing data, how do I not use the same data more than once in a test?


#1

Depending on the system under test(SUT), it’s often a requirement to not use the same data more than once in a test or at least ensure that Virtual Users(VUs) are not concurrently using the same data, such as login credentials. To do this we must calculate a unique number for the VUs to use during the test. I’ll share one example as a reply, but please add any methods you may use for your use case.


#2

As mentioned above, in order to prevent collisions between VUs accessing data from an external source, we need to calculate a unique number per VU iteration. Luckily, we have a few pieces of data we can use to calculate this. k6 provides the ID of VUs per load generator(k6 instance) as well as an iteration for each VU.

__VU is the ID of a VU. It is 1 based and assigned sequentially as VUs ramp up. Every VU on a load generator will have a unique VU ID.
__ITER is 0 based and increases sequentially as the default function is completed by VUs. Every VU will have their own iteration count.

Consider this example, with my script uniqueNum.js:

import http from "k6/http";
import { sleep } from "k6";

export default function() {
  http.get("http://test.loadimpact.com");
  console.log(`VU: ${__VU}  -  ITER: ${__ITER}`);
  let uniqueNumber = __VU * 100 + __ITER -100 ;
  console.log(uniqueNumber);
  sleep(1);
};

If I run the above script k6 run uniqueNum.js -i 10 -u 10 I will see in the console that each VU will start logging unique numbers in my console window, separated be 100. Resulting in no collisions. I can use this number to select a position from an external file.

/*
    Separate file where contents of data.json follows this pattern:
*/
    {
        "users": [
            { username: "test", password: "qwerty" },
            { username: "test", password: "qwerty" }
        ]
    }

Then, if our script looked something like:

const data = JSON.parse(open("./data.json"));

export default function() {
    let uniqueNumber = __VU * 100 + __ITER;
    let user = data.users[uniqueNumber];
    console.log(data.users[uniqueNumber].username);
}

We are now accessing a unique position per iteration and per virtual user.

Some things to keep in mind regarding the above method:

  • In our calculation of uniqueNumber, 100 would be the maximum iterations VUs can make before collisions. My selection of it was arbitrary here, you can decrease it or increase it based on need. You may know your test will never exceed 20 iterations per VU
  • The higher the above number, the larger your source file must be. A test with 200 VUs would need 20k lines/rows of unique data if all iterations were completed
  • In the Load Impact Cloud, a maximum of 200 VUs are assigned per load generator. So you would need to take LI_INSTANCE_ID into account when calculating unique values. More info on Load Impact env variables here