Grafana k6 and ASP.NET Core: A Practical Guide to Load & Stress Testing
Tags: netcore, aspnetcore, csharp, testing
Published: 2023-08-07 20:59:14

Performance testing is a critical aspect of the development process, it helps ensure that our applications can handle varying levels of traffic and deliver a smooth user experience under heavy loads.

In this article, we will explore how to perform load and stress testing on ASP.NET Core 6.0 applications using Grafana k6, an open-source performance testing tool.

---

## Understanding Load and Stress Testing

Load and stress testing are both types of performance testing, but they focus on evaluating the performance of a system under different levels of load and stress conditions. Let’s understand each of them.

## Load Testing

Load testing involves assessing the performance of a system under expected and anticipated user loads. The main goal is to determine how well the system performs when multiple users access it simultaneously.

**Key aspects**

- Scenarios: Test scenarios are designed to simulate real-world user behavior and usage patterns, including different types of user actions (e.g., browsing, searching, purchasing).
- Load Levels: Gradually increase the number of virtual users (simulated users) to apply load on the system and observe how it responds. The load can be constant or vary over time (ramp-up or ramp-down scenarios).
- Metrics: Common metrics in load testing include response time, throughput (transactions per second), error rates, and resource utilization (CPU, memory, etc.).
- Objective: The primary objective is to ensure that the system meets performance requirements, maintains acceptable response times, and handles the expected number of users without crashing or degrading significantly.

## Stress Testing
Stress testing, on the other hand, assesses the system’s behavior under extreme conditions beyond its normal operating capacity. The goal is to identify the system’s breaking point, where it starts to exhibit performance degradation or fails altogether.

**Key aspects**

- High Load Levels: Apply a load that exceeds the system’s designed capacity, testing its resilience and ability to recover from such conditions.
- Breaking Point: Aims to find the point at which the system starts to exhibit issues, such as increased response times, errors, or crashes.
- Recovery Testing: After reaching the breaking point, stress tests may evaluate how well the system recovers once the load is reduced to normal levels.
- Objective: The primary objective is to identify the system’s weaknesses, bottlenecks, and failure points, allowing developers and administrators to make necessary improvements and enhance the system’s robustness.

## Why Grafana k6?
k6 is a powerful and user-friendly load-testing tool that has gained significant popularity in the developer community. It offers a simple yet expressive JavaScript scripting language, making it easy to write and maintain test scripts. With its support for modern protocols and ability to scale to thousands of virtual users, k6 is an excellent choice for load and stress testing in .NET applications.

## Setting Up the Environment
Let's install Grafana k6 by following the official _[installation guide](https://k6.io/docs/get-started/installation/)_.

## Writing Load Test Scripts
Using k6, we can create test scripts that simulate user behavior and generate realistic loads on our application. It allows us to define scenarios, set up HTTP requests, and perform assertions to validate the responses.

Let's create a JS file called _**load_test.js**_:

```
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
    stages: [
        { duration: '1m', target: 100 }, // Ramp-up to 100 virtual users over 1 minute
        { duration: '3m', target: 100 }, // Stay at 100 virtual users for 3 minutes
        { duration: '1m', target: 0 },   // Ramp-down to 0 virtual users over 1 minute
    ],
    thresholds: {
        http_req_duration: ['p(95)<300'], // 95% of requests must complete within 300ms
    },
};

export default function () {

    var response = http.get('https://localhost:7071/api/books'); // HTTP Get all books

    check(response, {
        'is status 200': (x) => x.status === 200 // An assertion
    });

    sleep(1); // Wait for 1 second between each request
}
```

For more info about _[stages and configuration](https://k6.io/docs/)_

## Writing Stress Test Scripts
Creates a JS file called _**stress_test.js**_:

```
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
    stages: [
        { duration: '5s', target: 5 },    // Stage 1(5 seconds): Ramp - up to 5 virtual users over 5 seconds.
        { duration: '30s', target: 5 },   // Stage 2 (30 seconds): Stay at 5 virtual users for 30 seconds.
        { duration: '5s', target: 50 },   // Stage 3 (5 seconds): Ramp-up to 50 virtual users over 5 seconds.
        { duration: '30s', target: 50 },  // Stage 4 (30 seconds): Stay at 50 virtual users for 30 seconds.
        { duration: '5s', target: 100 },  // Stage 5 (5 seconds): Ramp-up to 100 virtual users over 5 seconds.
        { duration: '30s', target: 100 }, // Stage 6 (30 seconds): Stay at 100 virtual users for 30 seconds.
        { duration: '5s', target: 300 },  // Stage 7 (5 seconds): Ramp-up to 300 virtual users over 5 seconds.
        { duration: '30s', target: 300 }, // Stage 8 (30 seconds): Stay at 300 virtual users for 30 seconds.
        { duration: '5s', target: 0 },    // Stage 9 (5 seconds): Ramp-down to 0 virtual users over 5 seconds.
    ],
    thresholds: {
        http_req_duration: ['p(95)<1000'], // 95% of requests must complete within 1000ms
        http_req_failed: ['rate<0.1'],     // Request failure rate should be less than 0.1%
    },
};

export default function () {
    var response = http.get('https://localhost:7071/api/books'); // HTTP Get all books

    check(response, {
        'is status 200': (x) => x.status === 200 // An assertion
    });

    sleep(0.1); // Wait for 0.1 second between each request (adjust as needed for higher stress)
}
```

**ASP.NET Core API folder structure**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q11xv1kqqbgijx5flsh1.png)

## How To Run The Tests
The first thing we need to do is to start our API, let’s run **_dotnet run -c release_**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqbgubiedxqv2skxtu2q.png)

Let’s proceed with the test. To begin, open a new console window and navigate to the API folder. Next, execute the following k6 command in the console

```
k6 run load_test.js
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o47ijjbapwi2cuxa6s88.png)

During the test execution, k6 will collect various performance metrics, including response times, throughput, and error rates. These metrics will help us assess the application’s behavior under load and identify any performance bottlenecks.

The process above it is only for the load tests, If you want to run the stress tests, just run **_k6 run stress_test.js_**

## Analyzing Test Results
After the load and stress tests are complete, it’s time to analyze the results. Grafana k6 provides detailed reports and visualizations that help us understand the application’s performance characteristics. We can inspect metrics like response time distributions, error rates, and trends to pinpoint areas that need improvement.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fskh49afhi6vx52nkr0e.png)


**http_req_duration**, the end-to-end time of all requests (that is, the total latency)

**http_req_failed**, the total number of failed requests

**iterations**, the total number of iterations

Based on the insights gained from the test results, We can fine-tune our application, optimize its performance, and make it more resilient to handle higher user loads.

---

## Final Thoughts
Grafana k6 is a powerful tool that helps us to ensure our applications can handle the expected user loads without compromising performance. We can simulate realistic scenarios, analyze performance metrics, and identify and address potential issues before they impact the final users.

**_For more info: https://k6.io/docs/_**

---

## Thanks for reading!
Through my articles, I share Tips & Experiences on web development, career, and the latest tech trends. Join me as we explore these exciting topics together. Let’s learn, grow, and create together!

➕More article about [Programming, Careers, and Tech Trends.](https://medium.com/@andytechdev)

🔔 Follow me on [Medium](https://medium.com/@andytechdev) | [Twitter ](https://twitter.com/andytechdev)