The problem is not that testing is the bottleneck. The problem is that you don’t know what’s in the bottle. That’s a problem that testing addresses.
— Michael Bolton, author, “Rapid Software Testing.”
In this blog post, I explore what I have learned from my brief rendezvous with k6, which is said to make load testing as easy as unit testing. And I am pleased to report that I am thoroughly enjoying it! Here I’ll describe my experience with the tool as part of an application modernization project, detailing what I learned and the steps I took along the way.
In the past couple of quarters, my team was working on a project to decompose a legacy monolith service. Our goal was to replace it by developing new micro/mini RESTFul web services. Because of the day-to-day support overhead, performance issues, and difficulties delivering any change in production quickly, we made a strategic decision to split the legacy project. One MySQL database was supporting the three different services and multiple MapReduce processing jobs, creating a single point of failure for several products.
My team and I started with the smallest and independent API resources to disintegrate them from the monolith. After thoroughly reviewing all the pieces, we started working on our schema design and made necessary changes in the internal APIs design while making sure that all the features of our public APIs remained passive. Soon our new service was ready.
The main challenges to address ahead of deployment were:
- Conduct passivity check
- Improve performance and performance measurement
- Reduce maintenance and support overhead
- Estimate resource utilization for cost optimization
- Plan release to production with little to no downtime
I used Home Brew to install the k6 libraries on my MacBook and was ready to roll in less than a minute. (Figure 1)
Figure 1. Home Brew Install
As a Java developer, the learning curve is gentle, and I found the k6 documentation both robust and well-written. I was able to bang out my first unit test in just a few minutes and to later enhance the code to load test the service. It was love at first sight. Even better, k6 isn’t a browser-based utility—I could run the test on a command-line tool with a simple one-line command.
I have used other testing tools like Apache Benchmark, Jmeter, Gatling, and Postman, but k6 outshines them all with its ease of writing workflows using various operations provided by a service. Adding field validations, asserting outputs, generating dynamic dataset, and debugging the tests were all likewise very easy compared to other tools I have used in the past.
My First K6 Test
Figure 2. First Load Test
Note that I skipped other parts of my test to focus on the important details and show the ease of writing a test.
Now to run the test, I used k6 options to call a GET /Consumers API and run 10 iterations for 10 virtual users. I used the check function provided by the k6 library to assert the response HTTP code. For more available options, please refer to k6 Options.
Figure 3. Running the Test
The summary provided by k6 is self-explanatory, we can see how many requests k6 generated, the success request rate, and many other important metrics. The result summary looks like this (Figure 4):
Figure 4. The Result Summary
For more details about each metric please check Metrics. This resource also manifests many other output metrics based on your test configuration.
I used k6 and its features to work through with the challenges mentioned above. Over time I was able to increase the level and complexity of testing, as follows:
- For the passivity check, I asserted the API response under various load conditions and by using all known workflows.
- I have used k6 while local, dev, and QA environment to perform unit and load testing. After running the performance test using k6, I used NewRelic to compare the performance of legacy and new services by feeding the service logs to it. I presented the before and after performance comparison to all the stakeholders using the service.
- I ran a k6 test with a heavier load than our production traffic to identify the resources that we will need to run the service effectively and efficiently. I used the Grafana dashboard to generate a report of resource utilization and cost to run the service.
- I documented the timelines needed to roll out the changes to production by running various test scenarios. This helped me successfully communicate the plan to all the stakeholders.
- After production deployment and before enabling the service to end-users, I was able to run my test in production without affecting other businesses. This allowed me to test the correctness of the software and clean up the test data at the end of the testing cycle.
K6 integrates with many test visualization tools, though I have yet to explore them as my k6 journey has just started. In fact, that’s my biggest complaint. Unlike Gatling, k6 lacks a graphical result summary that does not require a third-party integration.
Overall, k6 has helped me up my game in performance testing—it turns out I had nothing to worry about! I was able to pick up the following pro tips, which helped me during my journey:
- Use environment variables to make your test dynamically accept Dev/Staging/Prod Configs, if there are any.
- If k6 cannot reach out to your API running behind a proxy server, export the HTTP_PROXY option before running the test, as shown in Figure 5:
Figure 5. Exporting the HTTP_Proxy Option
Finally, I learned there is nothing to stop me, as a developer, from adopting testing tools that can speed me up at the same time they help me deliver higher quality results.
References: k6: Load Testing for Engineering Teams
About The Author
Shradha Khard is an Associate Lead Software Engineer at Cerner Corporation. An industry leader cloud evangelist who is customer obsessed, product focused, and detail oriented, Khard is passionate about workplace equality and women’s growth in the IT sector. Her most precious possessions are her two daughters.