Introduction
In any enterprise-grade web application, ensuring performance under real-world traffic conditions is as important as developing the core functionality. Performance degradation under heavy load can lead to poor user experience, lost customers, and even downtime during critical business operations.
This article focuses on Performance Benchmarking and Stress Testing using two of the most widely adopted tools K6 and Apache JMeter.
We’ll explore how to set up these tools, run effective load and stress tests, interpret results, and integrate testing into a CI/CD pipeline for ASP.NET Core and Angular applications.
What is Performance Testing?
Performance testing is the process of evaluating how a system behaves under varying workloads. It identifies bottlenecks, scalability issues, and performance thresholds before an application goes live.
Common Types of Performance Tests
| Type | Purpose | Example |
|---|
| Load Testing | Measures system performance under expected load | 1000 concurrent users logging in |
| Stress Testing | Evaluates system stability beyond normal load | Gradually increase users until failure |
| Spike Testing | Tests reaction to sudden traffic increase | Flash sale or sudden API surge |
| Endurance Testing | Checks performance over an extended period | App stability for 24-hour uptime |
| Scalability Testing | Determines how performance scales with resources | Increasing CPU/memory instances |
Why K6 and JMeter?
Both K6 and JMeter are open-source, developer-friendly tools for load testing web apps and APIs.
| Feature | K6 | Apache JMeter |
|---|
| Language | JavaScript | Java |
| Ease of Setup | Lightweight CLI tool | GUI + CLI |
| Scripting | JS-based | XML Test Plans |
| Integration | Great with CI/CD | Extensive plugin ecosystem |
| Reporting | Built-in metrics and Grafana dashboards | CSV, HTML, or custom reports |
Technical Workflow
Performance Testing Lifecycle:
[Define Performance Goals]
↓
[Design Test Scenarios]
↓
[Configure K6 / JMeter]
↓
[Execute Load and Stress Tests]
↓
[Analyze Results & Identify Bottlenecks]
↓
[Optimize Code, Queries, or Infrastructure]
↓
[Re-Test and Validate Performance]
Setting Up K6 for Benchmarking
K6 is a modern, scriptable load testing tool built with performance and automation in mind. It allows developers to write tests in JavaScript and easily integrate with DevOps pipelines.
Step 1: Install K6
For Windows
choco install k6
For Linux/Mac
brew install k6
Step 2: Create a Test Script
Create a file named load_test.js
import http from 'k6/http';
import { sleep, check } from 'k6';
export let options = {
stages: [
{ duration: '1m', target: 50 }, // ramp-up to 50 users
{ duration: '3m', target: 50 }, // stay at 50 users
{ duration: '1m', target: 0 } // ramp-down
]
};
export default function () {
let response = http.get('https://myapi.example.com/api/products');
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500
});
sleep(1);
}
Step 3: Run the Test
k6 run load_test.js
Step 4: Analyze Output
K6 provides metrics like:
You can also integrate with Grafana + Prometheus for live visualization.
Setting Up Apache JMeter
JMeter has been a long-time favorite for load testing web and enterprise APIs, offering a graphical interface and detailed reporting.
Step 1: Install JMeter
Download from: https://jmeter.apache.org/download_jmeter.cgi
Extract and run:
./bin/jmeter.sh
or on Windows:
jmeter.bat
Step 2: Create a Test Plan
Open JMeter GUI
Add Thread Group → define number of users, ramp-up, and loop count
Add HTTP Request Sampler → specify the API endpoint
Add View Results in Table or Summary Report listeners
Save the plan as api_test_plan.jmx
Step 3: Run the Test
From GUI, click Start, or run in command-line mode:
jmeter -n -t api_test_plan.jmx -l results.jtl -e -o ./report
Step 4: Analyze Results
The JMeter HTML report includes:
Response time distribution
Throughput (transactions/sec)
Error % per request
Active thread count
Server resource utilization
ASP.NET Core API Benchmark Example
Let’s take an example of a simple ASP.NET Core Web API:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static readonly List<string> Products =
Enumerable.Range(1, 100).Select(i => $"Product {i}").ToList();
[HttpGet]
public IActionResult Get() => Ok(Products);
}
Run the above API locally and use either K6 or JMeter to simulate 500+ users calling /api/products concurrently.
After execution, you’ll observe:
This helps identify if you need to optimize:
Database queries (e.g., indexing or caching)
Middleware configurations
Thread pool and Kestrel settings
API compression or response caching
Integration with CI/CD Pipelines
K6 Integration Example (Jenkins or GitHub Actions):
name: Load Test
on:push:
branches: [ main ]
jobs:load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install K6
run: sudo apt install -y k6
- name: Run Load Test
run: k6 run load_test.js
This ensures every deployment is automatically validated for performance before going live.
JMeter Integration Example (Jenkins):
Add a Jenkins stage:
stage('Performance Test') {
steps {
sh 'jmeter -n -t tests/api_test_plan.jmx -l results.jtl -e -o reports/'
}
}
Benchmarking Metrics to Track
| Metric | Description | Ideal Range |
|---|
| Average Response Time | Time taken per request | < 500ms |
| Throughput (RPS) | Number of successful requests/sec | Higher is better |
| Error Rate | % of failed requests | < 1% |
| CPU/Memory Usage | Server resource utilization | < 70% |
| p(95) Latency | 95th percentile response time | Consistent performance |
Optimizing Based on Results
After identifying bottlenecks:
Use Response Caching and MemoryCache in ASP.NET Core
Optimize EF Core queries and add database indexes
Introduce Redis caching for frequently accessed data
Implement CDN caching for static Angular assets
Enable HTTP/2 and GZip compression in the server configuration
Example optimization in Program.cs:
builder.Services.AddResponseCaching();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(60)
};
await next();
});
Best Practices
Always test in an environment similar to production.
Use realistic user behavior (think-time, varied endpoints).
Gradually increase load to identify thresholds.
Test with both authenticated and anonymous users.
Include database and external API latency in analysis.
Run regular tests after feature changes or infrastructure updates.
Conclusion
Performance benchmarking and stress testing are not optional — they are an integral part of software quality assurance.
By using K6 for scriptable, developer-friendly load testing and JMeter for GUI-based comprehensive tests, developers can validate the resilience and scalability of both ASP.NET Core backends and Angular frontends under real-world conditions.
When integrated into your CI/CD pipeline, these tools ensure that performance regressions are caught early resulting in faster, more reliable, and enterprise-ready web applications.