The provided content is an in-depth guide on using k6, an open-source tool for load testing APIs, which covers installation, scripting, execution, and various testing strategies.
Abstract
The article "An Introduction to k6: An API Load-Testing Tool" serves as a comprehensive tutorial for developers to perform load and stress testing on RESTful APIs using k6. It explains the tool's capabilities for smoke, load, stress, spike, and soak testing. The guide details the setup process for different operating systems, the scripting of test cases in JavaScript, and the execution of these scripts to simulate various user loads. It also discusses the life cycle of a k6 test, including initialization, virtual user (VU) execution, and teardown phases. The article further elaborates on configuring test options, using HTTP methods for API calls, and implementing checks to assert response statuses. Practical examples and references to k6 documentation are provided to assist users in mastering the tool for effective API performance testing.
Opinions
The author emphasizes the flexibility of k6, particularly its support for JavaScript and TypeScript for writing test scripts.
k6 is praised for its ability to simulate real-world scenarios through different types of testing, such as spike testing to handle sudden traffic surges.
The article suggests that k6's built-in HTTP module simplifies the process of making API requests and checking responses.
The author advocates for the use of sleep statements to mimic actual user behavior and recommends using k6's check function for response validation without halting the execution.
The importance of understanding and configuring Virtual User (VU) levels is highlighted for accurate load testing.
The author provides a positive outlook on k6's staged testing feature, which allows for ramping up and down VUs to simulate fluctuating traffic patterns.
The article concludes by reiterating the value of k6 as a tool for ensuring API reliability and performance, suggesting that readers will benefit from its use in their projects.
By reading this piece, you’ll learn to perform load and stress testing on your RESTful API using a free and open-source load-testing tool called k6. k6 was previously known as Load Impact and is a full-fledged tool for:
Smoke testing — verify that your system doesn’t throw errors under a minimal load
Load testing — access the performance of your system during normal and peak loads
Stress testing — verify the reliability and stability of your system under a heavy load or extreme conditions
Spike testing — access the performance of your system when there’s a sudden surge of traffic
Soak testing — verify the reliability and stability of your system over an extended period of time
k6 is a great tool if you prefer to code the testing scripts in JavaScript. Also, it does have template support for TypeScript as well. You can even generate testing scripts from OpenAPI or Postman.
Let’s proceed to the next section for the setup and installation.
Setup
Installation is quite straightforward, although it depends to a degree on the operating system of your machine.
Windows
k6 comes with its own MSI installer for Windows users. Simply download the installer via the link below. Install it normally, and you’re good to go.
You can install k6 via the following command (use either dnf or yum for older version):
sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6
You need to disable the verification when installing on CentOS older than version 8:
sudo yum install --nogpgcheck k6
Test the Life Cycle
In this section, we’re going to learn the basic concepts behind k6. Each k6 test consists of four distinct life cycles:
init
setup
VU (virtual user)
teardown
k6 requires each test script to contain at least one default function, representing the entry point for the VU code. VU will call the VU code over and over again until all conditions are fulfilled.
On the other hand, init code will only run once per VU. Apart from that, the setup and teardown cycles will be called only once per test — at the start and end of the whole test life cycle.
You might be wondering about the differences between init and setup. Unlike init, you can actually call all of the k6 APIs, such as HTTP requests, in setup and teardown. For example, you can make a call in the setup code to obtain a token that’ll be used inside of the VU code.
HTTP Requests
HTTP GET request
You can define your first test case by utilizing the built-in http module. Create a new JavaScript file in your working directory. I’ll just call it script.js. Then, add the following code, which represents a simple GET request:
export default function () {
http.get('http://example.com/test');
sleep(1);
}
Each VU will execute the code inside the default function sequentially from start to end. Once it has reached the end, it’ll loop back, and the process will be repeated all over again.
It’s always a good idea to pace out your VUs by adding a sleep statement at the end of the default function. This simulates how real users use your system. You can set the value lower to 0.1 for simulating aggressive behaviors. If you intend to simulate users that constantly call your API, simply remove the sleep statement.
If you don’t have an API at the moment and just want to test k6, you can use the following test API provided by k6:
http://test.k6.io
Run the following code in your terminal:
k6 run script.js
Result output
You should see the following output in your terminal
Image by the author
By default, k6 will collect the following metrics each time you run a test:
vus — number of active virtual users
vus_max — maximum virtual users allocated for the test
iterations — aggregated number of times the default function is called
iteration_duration — the total time it took to execute the default function
dropped_iterations — number of iterations that couldn’t be started
data_received — amount of data received
data_sent — amount of data sent
checks — rate of successful checks (will be discussed later)
In addition, it’ll generate the following output as well if you’re calling HTTP requests:
http_reqs — total requests generated by k6
http_req_blocked — time spent waiting for a free TCP connection before initiating the request
http_req_connecting — time spent establishing a TCP connection
http_req_tls_handshaking — time spent on TLS handshaking
http_req_sending — time spent on data sending
http_req_waiting — time spent waiting for a response from the remote host
http_req_receiving — time spent on data receiving
http_req_duration — total time for the request. It’s calculated based on http_req_sending + http_req_waiting + http_req_receiving.
You can specify other arguments as well. Simply run the following to get the full list of the available arguments:
k6 help
Available HTTP methods
At the time of this writing, k6 comes with the following HTTP methods.
Here’s another example of HTTP POST, which takes JSON data as its input parameters.
If you are instead to test it on a form-data submission. Simply change the content type to application/x-www-form-urlencoded.
Options
In fact, you can specify additional arguments when running k6 the command line. For example, the following command will run the test with 10 VUs.
k6 run--vus 10 script.js
Having said that, you can specify such options in your code as well — providing you with better control over it. Let’s use our first example, but this time, we’re going to test it with 10 VUs with a duration of five seconds instead.
Slowly transitioning to 10 VUs in the next 70 seconds
Going from 10 to 0 VUs in the last 10 seconds
Options (load testing)
For load testing, you should ramp up the VU to a good amount and maintain it for a fixed period of time before ramping it down to 0. Have a look at the following example, which uses 100 VUs.
On the other hand, stress testing involves the constant ramping up of VUs gradually over a period of time. You can start with 100 VUs and then increment it by 100 VUs each time. Then, you ramp it down as part of the recovery phase.
Notice that I’ve ramped up from 100 to 1,000 VUs within a 10-second time frame. This helps to evaluate the performance of our system when there’s a sudden surge of users.
Checks
k6 provides a way for you to assert the returned response. It’s called check. Please note that check doesn’t halt the execution.
HTTP response
For your information, each HTTP method will return an HTTP response that contains the following:
body
headers
status
timings
timings.blocked
timings.connecting
timings.tls_handshaking
timings.sending
timings.waiting
timings.receiving
timings.duration
Checking if status is 200
The most useful fields are body and status. You can simply assign the returned HTTP response to a variable and check if its status is 200 as follows:
import { check } from 'k6';
import http from 'k6/http';
exportdefaultfunction () {
let res = http.get('http://example.com/test');
check(res, {
'is status 200': (r) => r.status === 200,
});
}
Conclusion
Let’s recap what we’ve learned today.
We started off with installing k6 on our local machine based on the operating system.
Next, we explored the fundamental concepts behind k6 — topics like testing the life cycle, which consists of four parts.
We moved onto creating a simple test scripts based on the built-in http module provided by k6. This allows us to make different HTTP methods call to test our APIs.
After that, we learned to configure options to setup load testing, stress testing and even spike testing. Also, we learned to configure and adding assertion to our code via check function.
Thanks for reading — I hope to see you again in the next article!