claria.tools.integrated-test-runner 1.1.1-build.20260814.1
Build Information
| Provenance | Azure DevOps Pipeline |
| Owner | kntera (Yan Boivin) |
| Date de compilation | 2026-08-14 15:48:39 UTC |
| Version | 1.1.1.20260814.1 |
| SHA256 | 5708f0e2209552659a98441e82960ffb802a5f1a |
Integrated Test Runner
Outil de tests d'intégration en ligne de commande pour valider des API REST.
Il exécute des fichiers .http (format REST Client / JetBrains HTTP) et permet d'écrire des assertions et des scripts C# directement dans les fichiers de test.
Contexte
Les tests d'intégration classiques nécessitent souvent un projet de test séparé avec beaucoup de boilerplate. Cet outil adopte une approche différente : les scénarios sont décrits dans des fichiers .http lisibles, qui combinent les appels HTTP et les scripts de validation C# dans un seul fichier.
Cas d'usage typique :
- Valider un flux complet sur une API (créer une ressource → la récupérer → la modifier → la supprimer)
- Partager des variables entre les requêtes (ex. : capturer l'
idd'une ressource créée pour l'utiliser dans les requêtes suivantes) - Lancer l'application à tester automatiquement avant les tests, y compris une base SQL LocalDB
Utilisation
IntegratedTestRunner.Console.exe [--debug] [--config <config.json>] <pattern|fichier.http>
| Argument | Description |
|---|---|
<pattern> |
Chemin vers un fichier .http ou un pattern glob (ex. tests/**/*.http) |
--config <path> |
Fichier de configuration JSON (optionnel) |
--debug |
Affiche les détails des requêtes et réponses |
Exemples :
# Exécuter un seul fichier
IntegratedTestRunner.Console.exe tests/transactions.http
# Exécuter tous les fichiers .http d'un dossier
IntegratedTestRunner.Console.exe "tests/**/*.http"
# Avec configuration (démarrage de l'application)
IntegratedTestRunner.Console.exe --config testconfig.json "tests/**/*.http"
# Mode debug
IntegratedTestRunner.Console.exe --debug tests/transactions.http
Sortie console
L'exécutable affiche les résultats au fur et à mesure de l'exécution, groupés par dossier, puis imprime un résumé global à la fin.
Format ligne par ligne
./tests/api/
create-transaction.http ... OK (142ms)
get-transaction.http ... OK (98ms)
delete-transaction.http ... [AssertionException] Expected 204 but got 200 (75ms)
<réponse HTTP brute affichée ici en cas d'échec>
./tests/auth/
login.http ... OK (203ms)
refresh.http ... INCONCLUSIVE: Token non encore supporté en environnement de test. (11ms)
| Résultat | Format affiché |
|---|---|
| Succès | ... OK (Xms) |
| Échec | ... [NomException] Message d'erreur (Xms) suivi du corps de la réponse HTTP |
| Non concluant | ... INCONCLUSIVE: Message (Xms) |
Résumé final
À la fin de l'exécution, un résumé global est affiché :
─────────────────────────────────────────
Tests : 5 OK : 3 (60%) FAILED : 1 (20%) INCONCLUSIVE : 1 (20%)
Total : 1.23s Average : 246ms
─────────────────────────────────────────
| Champ | Description |
|---|---|
Tests |
Nombre total de fichiers .http exécutés |
OK |
Tests terminés sans erreur |
FAILED |
Tests ayant levé une exception (assertion ou HTTP) |
INCONCLUSIVE |
Tests marqués comme non concluants via Assert.Inconclusive() |
Total |
Durée totale de l'exécution |
Average |
Durée moyenne par test |
Structure d'un fichier .http
Un fichier .http contient une ou plusieurs requêtes séparées par ---.
Chaque requête peut être suivie d'un bloc script C# (délimité par ```).
### Nom de la requête (optionnel)
MÉTHODE URL
En-tête: Valeur
{ corps JSON }
``` csharp
// script de validation post-requête
Requête suivante
...
### Formats de corps supportés
| `Content-Type` | Comportement |
|---|---|
| `application/json`, `text/plain`, etc. | Corps envoyé tel quel en UTF-8 |
| `multipart/form-data; boundary=...` | Corps parsé et envoyé comme `MultipartFormDataContent` — chaque partie délimitée par le `boundary` est transmise individuellement |
---
### Substitutions de variables
Dans les URLs, en-têtes et corps, deux types de substitutions sont disponibles :
| Syntaxe | Description |
|---|---|
| `{{env:clé}}` | Valeur stockée dans l'environnement partagé par un script précédent |
| `{{code:expression}}` | Expression C# évaluée à l'exécution |
```http
### Récupérer la transaction créée
GET http://localhost:5086/api/transactions/{{env:transaction.publicId}}
---
### Créer avec une date dynamique
POST http://localhost:5086/api/reservations
Content-Type: application/json
{
"date": "{{code:DateTime.UtcNow.AddDays(7).ToString("yyyy-MM-dd")}}"
}
Exemples de fichiers de test
Exemple 1 — Créer et chaîner des ressources
### Créer une transaction
POST http://localhost:5086/api/transactions
Content-Type: application/json
{
"advisorLicenseNumber": "LIC-00123",
"clientFirstName": "Marie",
"clientLastName": "Tremblay",
"plannedTransactionDate": "2026-06-15T00:00:00Z",
"businessUnit": "Mortgage",
"category": "Mortgage"
}
``` csharp
EnsureHttpSucceeded();
var publicId = jq.getString("$.publicId");
env.Add("transaction.publicId", publicId);
Récupérer la transaction créée
GET http://localhost:5086/api/transactions/{{env:transaction.publicId}}
EnsureHttpSucceeded();
Assert.AreEqual("Mortgage", jq.getString("$.category"));
Supprimer la transaction
DELETE http://localhost:5086/api/transactions/{{env:transaction.publicId}}
EnsureHttpStatusEqual(204);
---
### Exemple 2 — Utiliser des données générées aléatoirement
```http
### Créer un client avec des données fictives
POST http://localhost:5086/api/clients
Content-Type: application/json
{
"firstName": "{{code:new Bogus.Faker("fr_CA").Name.FirstName()}}",
"lastName": "{{code:new Bogus.Faker("fr_CA").Name.LastName()}}",
"email": "{{code:new Bogus.Faker().Internet.Email()}}"
}
``` csharp
EnsureHttpSucceeded();
var clientId = jq.getString("$.id");
env.Add("clientId", clientId);
> **Note :** À l'intérieur des scripts, `Faker` est directement disponible (voir section [Fonctions disponibles dans les scripts](#fonctions-disponibles-dans-les-scripts)).
---
### Exemple 3 — Envoyer un formulaire multipart
```http
### Téléverser un fichier
POST http://localhost:5086/api/uploads
Content-Type: multipart/form-data; boundary=----boundary
------boundary
Content-Disposition: form-data; name="description"
Rapport mensuel
------boundary
Content-Disposition: form-data; name="file"; filename="rapport.txt"
Content-Type: text/plain
Contenu du fichier ici
------boundary--
``` csharp
EnsureHttpSucceeded();
var fileId = jq.getString("$.fileId");
env.Add("upload.fileId", fileId);
> **Note :** La valeur du `boundary` dans le `Content-Type` doit correspondre exactement aux marqueurs `--boundary` dans le corps.
> Chaque partie peut avoir ses propres en-têtes (`Content-Type`, `Content-Disposition`). L'en-tête `Content-Type` est optionnel par partie ; s'il est absent, la partie est traitée comme texte UTF-8.
---
### Exemple 4 — Tester une réponse d'erreur attendue
```http
### Tenter une création invalide
POST http://localhost:5086/api/transactions
Content-Type: application/json
{
"advisorLicenseNumber": ""
}
``` csharp
EnsureHttpStatusEqual(400);
var message = jq.getString("$.errors.AdvisorLicenseNumber[0]");
Assert.IsNotNull(message);
---
## Configuration
Un fichier de configuration JSON permet de démarrer automatiquement l'application à tester avant les tests.
### Structure
```json
{
"application": {
"path": "dotnet",
"arguments": "run --project ../MyApi",
"workingDirectory": "./src",
"readyWhenOutputContains": "Application started",
"startupTimeoutSeconds": 60,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Testing",
"FeatureFlags__NewCheckout": "true"
},
"sqlLocalDb": {
"instanceName": "MSSQLLocalDB",
"connectionStringEnvironmentVariable": "ConnectionStrings__DefaultConnection"
}
}
}
Propriétés
| Propriété | Type | Défaut | Description |
|---|---|---|---|
application.path |
string |
— | Exécutable à lancer (ex. dotnet) |
application.arguments |
string |
"" |
Arguments de la commande |
application.workingDirectory |
string |
Dossier courant | Répertoire de travail du processus |
application.readyWhenOutputContains |
string |
null |
Attend que cette chaîne apparaisse dans stdout/stderr avant de démarrer les tests. Si absent, attend 1 seconde. |
application.startupTimeoutSeconds |
int |
30 |
Délai maximal d'attente du signal de démarrage |
application.environmentVariables |
object |
{} |
Variables d'environnement supplémentaires à injecter dans le processus lancé (paires clé/valeur) |
application.sqlLocalDb.instanceName |
string |
"MSSQLLocalDB" |
Nom de l'instance SQL LocalDB à démarrer |
application.sqlLocalDb.connectionStringEnvironmentVariable |
string |
— | Variable d'environnement dans laquelle injecter la chaîne de connexion |
Exemple sans base de données
{
"application": {
"path": "dotnet",
"arguments": "run --project ../MyApi",
"readyWhenOutputContains": "Now listening on:"
}
}
Exemple avec variables d'environnement
{
"application": {
"path": "dotnet",
"arguments": "run --project ../MyApi",
"readyWhenOutputContains": "Now listening on:",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Testing",
"FeatureFlags__NewCheckout": "true"
}
}
}
Les variables définies dans
environmentVariablessont injectées en premier. La chaîne de connexion SQL LocalDB (si configurée) est injectée ensuite et peut écraser une variable du même nom.
Exemple avec SQL LocalDB
{
"application": {
"path": "dotnet",
"arguments": "run --project ../MyApi",
"readyWhenOutputContains": "Application started",
"startupTimeoutSeconds": 90,
"sqlLocalDb": {
"instanceName": "MSSQLLocalDB",
"connectionStringEnvironmentVariable": "ConnectionStrings__DefaultConnection"
}
}
}
Fonctions disponibles dans les scripts
Chaque bloc script C# a accès aux objets globaux suivants.
jq — Requêtes JSONPath sur la réponse
Permet d'extraire des valeurs de la réponse JSON de la requête courante.
| Méthode | Retour | Description |
|---|---|---|
jq.getString("$.champ") |
string? |
Valeur texte. null si la valeur JSON est null. Lève KeyNotFoundException si le chemin n'existe pas. |
jq.getStringArray("$.champ") |
string[] |
Tableau de valeurs texte. Fonctionne aussi avec les wildcards ($.items[*].id). Retourne [] si le chemin n'est pas trouvé. |
jq.getInt("$.champ") |
int? |
Valeur entière, null si absent. |
jq.getBool("$.champ") |
bool? |
Valeur booléenne, null si absent. |
jq.getBoolean("$.champ") |
bool? |
Identique à getBool, lève KeyNotFoundException si le chemin n'existe pas. |
jq.getDateTime("$.champ") |
DateTime? |
Valeur date/heure (ISO 8601), null si absent. |
var id = jq.getString("$.publicId");
var tags = jq.getStringArray("$.tags");
var amount = jq.getInt("$.amount");
var active = jq.getBool("$.isActive");
var date = jq.getDateTime("$.createdAt");
env — Variables partagées entre les requêtes
Dictionnaire Dictionary<string, string> persisté entre toutes les requêtes du fichier.
Permet de passer des valeurs d'une requête à la suivante.
// Stocker une valeur
env.Add("transaction.publicId", jq.getString("$.publicId"));
env["token"] = jq.getString("$.accessToken");
// Lire une valeur (dans un script suivant)
var id = env["transaction.publicId"];
Pour utiliser une valeur dans l'URL ou le corps de la requête suivante :
GET http://localhost:5086/api/items/{{env:transaction.publicId}}
Assert — Assertions de test
Lève une AssertionException (et fait échouer le test) si la condition n'est pas satisfaite.
| Méthode | Description |
|---|---|
Assert.AreEqual(expected, actual) |
Vérifie l'égalité |
Assert.AreNotEqual(notExpected, actual) |
Vérifie l'inégalité |
Assert.IsTrue(condition) |
Vérifie que la condition est vraie |
Assert.IsFalse(condition) |
Vérifie que la condition est fausse |
Assert.IsNull(value) |
Vérifie que la valeur est nulle |
Assert.IsNotNull(value) |
Vérifie que la valeur n'est pas nulle |
Assert.Contains(expected, actual) |
Vérifie qu'une chaîne en contient une autre |
Assert.Fail() |
Fait échouer le test immédiatement |
Assert.Fail(message) |
Fait échouer le test immédiatement avec un message explicatif |
Assert.Inconclusive() |
Marque le test comme non concluant (ni succès ni échec) |
Assert.Inconclusive(message) |
Marque le test comme non concluant avec un message explicatif |
Toutes les méthodes acceptent un paramètre message optionnel pour personnaliser le message d'erreur.
Assert.AreEqual("Mortgage", jq.getString("$.category"));
Assert.IsNotNull(jq.getString("$.publicId"));
Assert.IsTrue(jq.getInt("$.amount") > 0, "Le montant doit être positif");
Assert.Contains("Tremblay", jq.getString("$.clientLastName"));
Assert.Inconclusive — Test non concluant
Lève une InconclusiveException qui interrompt le test sans le comptabiliser comme un échec.
Utile pour signaler qu'un scénario ne peut pas être validé dans les conditions actuelles (fonctionnalité non encore disponible, données manquantes, prérequis non rempli, etc.).
La sortie affiche INCONCLUSIVE au lieu d'un message d'erreur.
// Sans message
Assert.Inconclusive();
// Avec message explicatif
Assert.Inconclusive("Fonctionnalité non encore déployée en environnement de test.");
// Exemple conditionnel
var status = jq.getString("$.status");
if (status == "pending")
Assert.Inconclusive($"La ressource est encore en attente (status={status}), test ignoré.");
Sortie correspondante :
./tests/
montest.http ... INCONCLUSIVE: Fonctionnalité non encore déployée en environnement de test.
EnsureHttpSucceeded() — Validation du statut HTTP 2xx
Vérifie que la réponse HTTP a un code de statut entre 200 et 299 (inclus).
Équivalent d'un Assert sur le code HTTP.
EnsureHttpSucceeded(); // Lève une exception si le statut n'est pas 2xx
EnsureHttpStatusEqual(code) — Validation d'un statut HTTP précis
Vérifie que le code de statut HTTP correspond exactement à la valeur attendue.
EnsureHttpStatusEqual(201); // Created
EnsureHttpStatusEqual(204); // No Content
EnsureHttpStatusEqual(400); // Bad Request (pour tester les erreurs attendues)
Faker — Génération de données fictives
Basé sur la librairie Bogus. Génère des données aléatoires réalistes pour les tests.
| Propriété | Description |
|---|---|
Faker.Name |
Noms de personnes (FirstName(), LastName(), FullName()) |
Faker.Internet |
Données internet (Email(), UserName(), Url(), Ip()) |
Faker.Phone |
Numéros de téléphone (PhoneNumber()) |
Faker.Address |
Adresses (City(), Country(), ZipCode(), StreetAddress()) |
Faker.Date |
Dates (Past(), Future(), Between(from, to)) |
Faker.Lorem |
Texte (Word(), Sentence(), Paragraph()) |
Faker.Finance |
Finances (Amount(), Currency(), Iban()) |
Faker.Company |
Entreprises (CompanyName(), Bs(), CatchPhrase()) |
Faker.Random |
Aléatoire générique (Number(), Guid(), Bool()) |
var email = Faker.Internet.Email();
var firstName = Faker.Name.FirstName();
var amount = Faker.Finance.Amount(100, 10000);
var phone = Faker.Phone.PhoneNumber("###-###-####");
env.Add("clientEmail", email);
env.Add("clientName", firstName);
Le
Fakerdans les scripts utilise la locale"en"par défaut.
Pour générer des données localisées, utilisez{{code:new Bogus.Faker("fr_CA").Name.FirstName()}}dans les substitutions de l'URL ou du corps.
No packages depend on claria.tools.integrated-test-runner.
| Version | Downloads | Last updated |
|---|---|---|
| 1.1.1-build.20260814.1 | 11 | 08/14/2026 |