HTTP plugin
This document will help you learn about NBomber.HTTP plugin in more detail.
Overview
NBomber.Http provides a simple API to define HTTP steps, calculate response size, apply assertions.
Installation
Add HTTP package into your project.
dotnet add package NBomber.Http
Create HTTP load test
- F#
- C#
open System
open System.Net.Http
open FSharp.Control.Tasks.NonAffine
open NBomber.Contracts
open NBomber.FSharp
open NBomber.Plugins.Network.Ping
open NBomber.Plugins.Http.FSharp
[<EntryPoint>]
let main argv =
// it's optional Ping plugin that brings additional reporting data
let pingConfig = PingPluginConfig.CreateDefault "nbomber.com"
let pingPlugin = new PingPlugin(pingConfig)
let httpFactory = HttpClientFactory.create()
let step = Step.create("simple step", clientFactory = httpFactory, execute = fun context ->
Http.createRequest "GET" "https://nbomber.com"
|> Http.withHeader "Accept" "text/html"
|> Http.withBody(new StringContent("{ some JSON }"))
|> Http.withCheck(fun response -> task {
return if response.IsSuccessStatusCode then Response.ok()
else Response.fail()
})
|> Http.send context
)
Scenario.create "nbomber-web-site" [step]
|> Scenario.withLoadSimulations [InjectPerSec(rate = 100, during = seconds 30)]
|> NBomberRunner.registerScenario
|> NBomberRunner.withWorkerPlugins [pingPlugin]
|> NBomberRunner.run
|> ignore
0 // return an integer exit code
using System;
using System.Net.Http;
using NBomber.Contracts;
using NBomber.CSharp;
using NBomber.Plugins.Http.CSharp;
using NBomber.Plugins.Network.Ping;
namespace CSharp
{
public class Program
{
static void Main(string[] args)
{
var pingPluginConfig = PingPluginConfig.CreateDefault("nbomber.com");
var pingPlugin = new PingPlugin(pingPluginConfig);
var httpFactory = HttpClientFactory.Create();
var step = Step.Create("simple step", clientFactory: httpFactory, execute: async context =>
{
var request =
Http.CreateRequest("GET", "https://nbomber.com")
.WithHeader("Accept", "text/html")
.WithBody(new StringContent("{ some JSON }"))
.WithCheck(async (response) =>
response.IsSuccessStatusCode
? Response.Ok()
: Response.Fail()
);
var response = await Http.Send(request, context);
return response;
});
var scenario = ScenarioBuilder
.CreateScenario("nbomber-web-site", step)
.WithLoadSimulations(Simulation.InjectPerSec(100, TimeSpan.FromSeconds(30)));
NBomberRunner
.RegisterScenarios(scenario)
.WithWorkerPlugins(pingPlugin)
.Run();
}
}
}
HTTP API
NBomber.Http provides HTTP API that can be used to create/send request and check response. It supports HTTP protocol specific concepts like HEADERS, BODY, VERSION.
HTTP Request
NBomber.Http provides a convenient way to define HTTP request and then send it.
- F#
- C#
let httpFactory = HttpClientFactory.create();
let step1 = Step.create("step 1", clientFactory = httpFactory, execute = fun context ->
Http.createRequest "GET" "https://nbomber.com"
|> Http.send context
)
let step2 = Step.create("step 2", clientFactory = httpFactory, execute = fun context -> task {
let step1Response = context.GetPreviousStepResponse<HttpResponseMessage>()
let headers = step1Response.Headers
let! body = step1Response.Content.ReadAsStringAsync()
return! Http.createRequest "GET" "https://nbomber.com"
|> Http.send context
})
var httpFactory = HttpClientFactory.Create();
var step1 = Step.Create("step 1", clientFactory: httpFactory, execute: async context =>
{
var request = Http.CreateRequest("GET", "https://nbomber.com");
var response = await Http.Send(request, context);
return response;
});
var step2 = Step.Create("step 2", clientFactory: httpFactory, execute: async context =>
{
var step1Response = context.GetPreviousStepResponse<HttpResponseMessage>();
var headers = step1Response.Headers;
var body = await step1Response.Content.ReadAsStringAsync();
var request = Http.CreateRequest("GET", "https://nbomber.com");
var response = await Http.Send(request, context);
return response;
});
HTTP Version
By default, NBomber.Http sets HTTP Version 1.1 but you can override this.
Http.withVersion "2.0"
HTTP Headers
By default, NBomber.Http sets no headers but you can override this.
Http.withHeader "Accept" "application/json"
HTTP Body
// here we set string content
Http.withBody(new StringContent json)
// here we set binary data
Http.withBody(new ByteArrayContent bytes)
HTTP Check Response
By default, NBomber.Http is using this check for every response but you can override it.
Http.withCheck(fun response -> task {
if response.IsSuccessStatusCode then
return Response.ok(response, statusCode = int response.StatusCode)
else
return Response.fail(statusCode = int response.StatusCode)
})
HTTP ClientFactory
NBomber.Http provides HttpClientFactory
abstraction that can be used to init a base HttpClient that will be used within your test.
note
NBomberHttpClientFactory creates only one instance of HttpClient and uses it for all steps. You can override it if you need it.
- F#
- C#
let httpFactory = HttpClientFactory.create();
let step1 = Step.create("step 1", clientFactory = httpFactory, execute = fun context ->
Http.createRequest "GET" "https://nbomber.com"
|> Http.send context
)
var httpFactory = HttpClientFactory.Create();
var step1 = Step.Create("step 1", clientFactory: httpFactory, execute: async context =>
{
var request = Http.CreateRequest("GET", "https://nbomber.com");
var response = await Http.Send(request, context);
return response;
});
HTTP Client Timeout
By default, NBomber.Http uses HttpClient with default timeout for 100 seconds. A Domain Name System (DNS) query may take up to 15 seconds to return or time out. You can adjust and set a cutom timeout.
note
Also, pay attention that NBomber Step has a default timeout for 1 second.
- F#
- C#
let myHttpClient = new HttpClient()
myHttpClient.Timeout <- seconds 5
let httpFactory = HttpClientFactory.create("my_http_factory", myHttpClient)
var myHttpClient = new HttpClient();
myHttpClient.Timeout = TimeSpan.FromSeconds(5);
var httpFactory = HttpClientFactory.Create("my_http_factory", myHttpClient);
Tracing
There may be situations when you need to trace your requests and responses. The NBomber.Http has built-in functionality for tracing every request/response. In order to start tracing you need to set minimum logging level to Verbose.
NBomberRunner.withLoggerConfig(fun () ->
LoggerConfiguration().MinimumLevel.Verbose()
)
Also, you can enable tracing via the infrastructure config file.
{
"Serilog": {
"MinimumLevel": "Verbose"
}
}
JSON parsing
To work with the JSON format, you can use any library you prefer. Here is a list of popular libraries:
Here is an example with using Newtonsoft.Json
, but you can use any other.
- F#
- C#
Http.createRequest "GET" url
|> Http.withCheck(fun response -> task {
let! jsonBody = response.Content.ReadAsStringAsync()
// parse JSON
let posts =
jsonBody
|> JsonConvert.DeserializeObject<PostResponse[]>
|> Option.ofObj
match posts with
| Some ps when ps.Length > 0 -> return Response.ok()
| -> return Response.fail()
})
var request = Http.CreateRequest("GET", url)
.WithCheck(async response =>
{
var jsonBody = await response.Content.ReadAsStringAsync();
// parse JSON
var users = JsonConvert.DeserializeObject<PostResponse[]>(jsonBody);
return users?.Length == 1
? Response.Ok()
: Response.Fail();
});
Best practices
- To test HTTP use LoadSimulation.InjectPerSec since usually web server is an open system. You can read more here.
- For debugging or tracing you can use LoadSimulation.KeepConstant with copies = 1 since for this simulation NBomber will use a single thread which is easier to debug.
- Use Ping plugin to get more info about networking.
- Convert your integration tests to load tests