On va voir comment avoir en quelques minutes des assertions qui vont vérifier les endpoints de notre API avec des scénarios de ce genre:
Feature: Create a new account
As a visitor,
I can create an account to access the game
Scenario: A visitor creates an account
When I fill the login form with
| email | password |
| [email protected] | Jh0nD0e! |
Then I can login with
| email | password |
| [email protected] | Jh0nD0e! |
Et des assertions du style:
[When("I fill the login form with")]
public async Task IFillTheLoginForm(Table table)
{
var row = table.Rows[0];
RegisterUserCommand registerUserCommand = new (row["email"], row["password"]);
var result = await _httpClient.PostAsJsonAsync("/api/users/register", registerUserCommand);
result.EnsureSuccessStatusCode();
}
Si vous utilisez Rider et l’extension Reqnroll, vous pouvez simplement créer un nouveau projet Reqnrol depuis le template et en quelques clics c’est fait !
2. Installation des dépendances
On va rajouter la dépendance à Microsoft.AspNetCore.Mvc.Testing dans notre projet Reqnroll. C’est elle qui va nous permettre d’avoir un client Http très facilement.
II. Configuration
Il va falloir dire qu’on veut lancer le client de test sur notre projet qui contient notre API. Pour se faire, on va dans le program.cs de notre API et on rajoute cette ligne tout à la fin:
public partial class Program { }
On va ensuite créer notre fichier contenant la définition de nos steps (UserStepDefinition.cs dans mon cas) puis initialiser notre client Http via le constructeur de notre classe:
[Binding]
public sealed class UserStepDefinitions
{
private readonly HttpClient _httpClient;
public UserStepDefinitions(WebApplicationFactory<Program> factory)
{
_httpClient = factory.CreateClient(new WebApplicationFactoryClientOptions());
}
}
Et c’est tout ! On peut dès à présent faire des vérifications sur nos endpoints.
Voici ma classe entière qui permet de lancer le scénario présenté en introduction:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.Mvc.Testing;
using Reqnroll;
using StrategyBrowserGameAPI.Command;
namespace AcceptanceTests.StepDefinitions;
[Binding]
public sealed class UserStepDefinitions
{
private readonly HttpClient _httpClient;
public UserStepDefinitions(WebApplicationFactory<Program> factory)
{
_httpClient = factory.CreateClient(new WebApplicationFactoryClientOptions());
}
[When("I fill the login form with")]
public async Task IFillTheLoginForm(Table table)
{
var row = table.Rows[0];
RegisterUserCommand registerUserCommand = new (row["email"], row["password"]);
var result = await _httpClient.PostAsJsonAsync("/api/users/register", registerUserCommand);
result.EnsureSuccessStatusCode();
}
[Then("I can login with")]
public async Task ICanLoginWith(Table table)
{
var row = table.Rows[0];
var loginRequest = new LoginRequest
{
Email = row["email"],
Password = row["password"]
};
var loginResponse = await _httpClient.PostAsJsonAsync("/login", loginRequest);
loginResponse.EnsureSuccessStatusCode();
var accessToken = await ExtractAccessToken(loginResponse);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var manageInfoResult = await _httpClient.GetAsync("/manage/info");
manageInfoResult.EnsureSuccessStatusCode();
}
private static async Task<string> ExtractAccessToken(HttpResponseMessage loginResponse)
{
var loginResponseAsString = await loginResponse.Content.ReadAsStringAsync();
var jsonDoc = JsonDocument.Parse(loginResponseAsString);
var accessToken = jsonDoc.RootElement.GetProperty("accessToken").GetString();
return accessToken;
}
}
Pour aller plus loin
Évidemment, dans mon cas très simple avec une BDD in memory et sans appels externes ça marche très bien mais dans vos applications professionnelles, vous avez sûrement un peu plus de dépendances que ça.
La lib Microsoft.AspNetCore.Mvc.Testing est bien faite et permet facilement d’ajouter de la personnalisation: peut-être que vous souhaitez utiliser une base in-memory pour les tests ou un substitut pour un service externe par exemple.
On ne l’abordera pas dans cet article mais ces exemples sont détaillés dans la doc officielle .Net.
Depuis .NET 9, le le support d’OpenAPI est directement inclus dans .NET et ne passe plus par les librairies Swagger par défaut (plus d’info sur ce choix ici si jamais ça vous intéresse).
De façons simplifiée, la librairie Swashbuckle.AspNetCore.Swagger faisait deux choses:
Générer un JSON au format OpenApi en scannant votre projet (c’est ce qui est inclus dans .NET mainte...
Description du problème
Par défaut, il n’est pas autorisé de faire des requêtes entre une application qui est dans un domaine A vers une autre qui serait dans un domaine B (pour des raisons de sécurité, il y a plus de détails dans les sources).
S...
Image prise sur Windows Central
Historique
Pour cet article je vais faire un mini REX sur l’écosystème de Microsoft pour les développeurs.
J’ai commencé à travailler avec les technologies Microsoft vers 2016. Pour situer, Windows 10 devait avoir �...
Photo by Jackson So on Unsplash
Dans ce court article je vais vous expliquer comment faire en sorte que votre formulaire généré avec le moteur de templating Razor ait bien le bon champ « action » et non un champ « action » vide.
...