No results for

Powered byAlgolia

Test life cycle

A k6 test has four distinct stages. A script always runs through these stages in the same order.

  1. Code in the init context prepares the script: loading files, importing modules, and defining functions.
  2. (Optional) The setup code runs, setting up the test environment (optional) and generating data.
  3. VU code runs in the default() function, running for as long and as many times as the options define.
  4. (Optional) The teardown code runs, postprocessing data and closing the test environment.

This orderset up, test, then tear downfollows the structure of many testing frameworks.

The four life cycle stages
1// 1. init code
2
3export function setup() {
4 // 2. setup code
5}
6
7export default function (data) {
8 // 3. VU code
9}
10
11export function teardown(data) {
12 // 4. teardown code
13}

Overview of the test stages

For more technical detail, see this page's subsequent sections.

Test stageUsed toExampleCalledRequired?
1. initLoad local files, import modules, declare global variablesOpen JSON file, Import moduleOnce per VU*Required
2. SetupSet up data for processing, share data among VUsCall API to start test environmentOnceOptional
3. VU codeRun the test function, usually defaultMake https requests, validate responsesOnce per iteration, as many times as the test options requireRequired
4. TeardownProcess result of setup code, stop test environmentValidate that setup had a certain result, send webhook notifying that test has finishedOnce per scriptOptional

* In cloud scripts, init code might be called more often.

The init stage

Before the test runs, k6 needs to initialize the test conditions. To prepare the test, the code in the init context:

  • Imports modules
  • Loads files from the local file system
  • Configures the test for all options
  • Defines functions for the default (VU), setup, and teardown stages (and for custom functions, too).

The init stage is required. Separating the init stage from the VU stage removes irrelevant computation from VU code, which both improves k6 performance and makes test results more reliable.

All code that is outside of a function is code in the init context. Code in the init context always executes first.

Examples of init code
1// init context: importing modules
2import http from 'k6/http';
3import { Trend } from 'k6/metrics';
4
5// init context: define k6 options
6export const options = {
7 vus: 10,
8 duration: '30s',
9};
10
11// init context: global variables
12const customTrend = new Trend('oneCustomMetric');
13
14// init context: define custom function
15function myCustomFunction() {
16 // ...
17}

The VU stage

Scripts must contain, at least, a default() function. The code inside this function is VU code.

Default/Main function
1export default function () {
2 // do things here...
3}

VU code runs over and over through the test duration.

VU code can make HTTP requests, emit metrics, and generally do everything you'd expect a load test to do. The only exceptions are the jobs that happen in the init context.

  • VU code does not load files from your local filesystem.
  • VU code does not import any other modules.

Again, instead of VU code, init code does these jobs.

The default function life-cycle

A VU executes the default() function from start to end in sequence. Once the VU reaches the end of the function, it loops back to the start and executes the code all over.

As part of this "restart" process, k6 resets the VU. Cookies are cleared, and TCP connections might be torn down (depending on your test configuration options).

Setup and teardown stages

Like default, setup and teardown functions must be exported functions. But unlike the default function, k6 calls setup and teardown only once per test.

  • setup is called at the beginning of the test, after the init stage but before the VU stage.
  • teardown is called at the end of a test, after the VU stage (default function).

You can call the full k6 API in the setup and teardown stages, unlike the init stage. For example, you can make HTTP requests:

Setup/Teardown with HTTP request
1import http from 'k6/http';
2
3export function setup() {
4 const res = http.get('https://httpbin.test.k6.io/get');
5 return { data: res.json() };
6}
7
8export function teardown(data) {
9 console.log(JSON.stringify(data));
10}
11
12export default function (data) {
13 console.log(JSON.stringify(data));
14}

Skip setup and teardown execution

You can skip the execution of setup and teardown stages using the options --no-setup and --no-teardown.

Skipping setup/teardown execution
1$ k6 run --no-setup --no-teardown ...

Using data from setup in default and init

Again, let's have a look at the basic structure of a k6 test:

Setup/Teardown
1// 1. init code
2
3export function setup() {
4 // 2. setup code
5}
6
7export default function (data) {
8 // 3. VU code
9}
10
11export function teardown(data) {
12 // 4. teardown code
13}

You might have noticed the function signatures of the default() and teardown() functions take an argument, referred to here as data.

Here's an example of passing some data from the setup code to the VU and teardown stages:

Setup/Teardown
1export function setup() {
2 return { v: 1 };
3}
4
5export default function (data) {
6 console.log(JSON.stringify(data));
7}
8
9export function teardown(data) {
10 if (data.v != 1) {
11 throw new Error('incorrect data: ' + JSON.stringify(data));
12 }
13}

For example, with the data returned by the setup() function, you can:

  • Give each VU access to an identical copy of the data
  • Postprocess the data in teardown code

However, there are some restrictions.

  • You can pass only data (i.e. JSON) between setup and the other stages. You cannot pass functions.
  • If the data returned by the setup() function is large, it will consume more memory.
  • You cannot manipulate data in the default() function, then pass it to the teardown() function.

It's best to think that each stage and each VU has access to a fresh "copy" of whatever data the setup() function returns.

Diagram showing data getting returned by setup, then used (separately) by default and teardown functions

It would be extremely complicated and computationally intensive to pass mutable data between all VUs and then to teardown, especially in distributed setups. This would go against a core k6 goal: the same script should be executable in multiple modes.