Vos tests API passent sur votre ordinateur portable. La vraie question est de savoir s'ils s'exécutent à chaque pull request, chaque fusion, chaque build nocturne, sans intervention humaine. Ce travail appartient à un exécuteur en ligne de commande (CLI runner). Il prend les tests que vous avez déjà rédigés et les exécute en mode sans tête dans votre pipeline, se termine avec un code de statut propre et écrit un rapport que votre tableau de bord CI peut lire.
Deux exécuteurs reviennent constamment lorsque les équipes mettent cela en place : le CLI Bruno et le CLI Apidog. Ils résolvent le même problème à partir de points de départ différents. Bruno est un client API open source, privilégiant l'approche Git native et le mode hors ligne, et son CLI exécute les fichiers .bru qui se trouvent dans votre dépôt. Apidog est une plateforme API tout-en-un, et son CLI exécute les scénarios de test visuels que vous construisez dans l'application. Les deux s'intègrent à GitHub Actions, GitLab CI, Jenkins et tout ce qui utilise Node.js. Les deux font échouer la build lorsqu'un test échoue. Les différences apparaissent dans la manière dont vous rédigez les tests, comment vous vous authentifiez et comment la définition des tests transite vers la CI.
Il s'agit d'une comparaison honnête, au niveau de la commande, des deux outils. Pas d'homme de paille. Bruno fait plusieurs choses vraiment bien, et vous verrez exactement où chaque exécuteur s'intègre avant d'en intégrer un dans votre pipeline.
En bref
- CLI Bruno (
@usebruno/cli, binairebru) exécute les fichiers.brudirectement depuis un dossier de votre dépôt Git. Il est open source, hors ligne et ne nécessite aucun compte ni jeton. Vous le pointez vers un répertoire et il exécute chaque requête et assertion qu'il y trouve. - CLI Apidog (
apidog-cli, binaireapidog) exécute les scénarios de test que vous concevez dans l'application Apidog, récupérés par ID à l'aide d'un jeton d'accès. Vous ne réécrivez pas les tests sous forme de code ; le scénario visuel est le test, et le CLI l'exécute en mode sans tête. - Les deux émettent des rapports JUnit, JSON et HTML, et les deux font échouer la build en cas de test échoué. Le XML JUnit est ce qui s'intègre aux tableaux de bord CI dans les deux cas.
- Choisissez Bruno si vous voulez tout dans le dépôt, zéro compte et un contrôle hors ligne complet des fichiers de test en texte brut.
- Choisissez Apidog si vous souhaitez une création visuelle, l'enchaînement de scénarios, la gestion d'environnements et des exécutions basées sur les données sans avoir à maintenir le code de test manuellement.
Le vrai problème : des tests qui existent mais ne sont jamais exécutés
Un test que vous exécutez manuellement est un test qui se dégrade. Quelqu'un l'a créé, il a passé une fois, puis il est resté intouché pendant que l'API évoluait en dessous. La solution n'est pas d'avoir plus de tests. Ce sont des tests qui s'exécutent automatiquement à chaque changement, avec un signal de réussite/échec sur lequel le pipeline peut agir.
Un exécuteur CLI est ce qui comble cette lacune. Il a besoin de trois choses pour être utile en CI : il doit s'exécuter sans interface graphique, il doit se terminer avec un code non nul si quelque chose échoue pour que la build devienne rouge, et il doit écrire un rapport lisible par machine afin que les réviseurs voient ce qui a échoué. Bruno et Apidog remplissent tous deux cette condition. Là où ils diffèrent, c'est en amont de la commande d'exécution, dans la façon dont le test a été écrit et où il réside.
Si vous mettez en place la CI à partir de zéro, les modèles plus larges d'automatisation des tests API en CI/CD méritent d'être lus en parallèle de cette comparaison. Ici, nous nous concentrons sur les deux exécuteurs eux-mêmes.
Ce que le CLI Bruno fait bien
L'ensemble de la conception de Bruno est native de Git. Chaque requête, environnement et assertion est un fichier .bru en texte brut sur le disque, à l'intérieur de votre dépôt, versionné comme tout autre fichier source. Ce modèle présente de réels avantages, et il est bon de les exposer clairement avant toute comparaison.
Vos tests vivent avec votre code. Une pull request qui modifie un endpoint peut modifier le test de cet endpoint dans le même diff, révisé par la même personne. Il n'y a pas de système séparé à synchroniser, pas de copie cloud qui pourrait s'éloigner de ce qui se trouve dans le dépôt. Les diffs sont lisibles car le format est textuel. Vous pouvez rechercher vos tests avec grep, les refactoriser avec les mêmes outils que ceux que vous utilisez pour le code, et résoudre les conflits de fusion dans un éditeur.
Il est également open source et hors ligne. Le CLI s'exécute entièrement sur votre machine ou votre exécuteur CI sans compte, sans connexion et sans jeton. Pour les équipes ayant des règles strictes de gestion des données ou des environnements isolés (air-gapped), c'est important. Le niveau payant de Bruno, Bruno Ultimate, ajoute des fonctionnalités d'équipe telles que le SSO et le SCIM, des intégrations de gestionnaires de secrets et des capacités d'audit, ce n'est donc pas seulement un outil de passionné. Mais le client principal et le CLI sont gratuits et autonomes, et c'est une force légitime.
L'installation se fait avec une seule commande :
npm install -g @usebruno/cli
Le binaire est bru. Vous exécutez une collection en le pointant vers le dossier qui contient vos fichiers .bru :
bru run --env staging
Exécuté depuis le répertoire de la collection, bru run exécute les requêtes qu'il y trouve. Ajoutez -r pour parcourir les sous-dossiers afin qu'il prenne en compte les requêtes imbriquées :
bru run -r --env staging
C'est la boucle principale. Pas d'ID, pas de jeton, pas de récupération à distance. Les fichiers du dossier sont les tests, et le CLI les exécute.
Nous avons abordé l'histoire plus large de Bruno dans ce qui rend Bruno différent en tant que client API git-native et où ses limites apparaissent pour les grandes équipes. Pour la CI spécifiquement, les forces mentionnées ci-dessus sont celles qui comptent.
Ce que le CLI Apidog fait bien
Apidog emprunte un chemin différent vers le même pipeline. Vous construisez visuellement des tests dans l'application Apidog : vous enchaînez les requêtes dans un scénario, ajoutez des assertions, extrayez une valeur d'une réponse pour la requête suivante, et bouclez le tout sur un fichier de données. Le CLI est l'exécuteur sans tête de ces scénarios. Il n'a pas son propre format de fichier. Il récupère le scénario que vous nommez par ID depuis votre projet Apidog et l'exécute exactement comme le ferait l'application.
L'avantage est que personne ne maintient deux représentations du même test. Le scénario dans le projet est le test. Vous le créez dans un constructeur visuel qui gère l'enchaînement des requêtes, l'extraction de variables et les assertions sans que vous ayez à écrire et déboguer des fichiers de script. Ensuite, le CLI exécute ce même scénario en CI. La boucle de création rapide et la boucle d'automatisation utilisent une source de vérité unique.
L'installation se fait avec une seule commande npm :
npm install -g apidog-cli
Le binaire est apidog. Une exécution typique nomme un scénario par ID, choisit un environnement et s'authentifie avec un jeton d'accès :
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -n 1 -r html,junit
Vous ne tapez pas ces ID à la main. Ouvrez le scénario de test, passez à son onglet CI/CD, générez un jeton d'accès, et Apidog construira la commande complète pour vous avec l'ID du scénario et l'ID de l'environnement déjà renseignés. Vous le copiez une fois, puis déplacez le jeton dans un secret de CI et le référencez comme $APIDOG_ACCESS_TOKEN. La référence complète des drapeaux se trouve dans le guide complet du CLI Apidog si vous voulez toutes les options au même endroit.
Le modèle basé sur les jetons est la différence la plus claire avec Bruno. Apidog exécute des tests stockés dans un projet que le CLI atteint via le réseau, authentifié. Bruno exécute des tests stockés sous forme de fichiers que le CLI lit depuis le disque. Ni l'un ni l'autre n'est faux ; ils conviennent à différentes configurations d'équipe.
Comparaison côte à côte
| Dimension | CLI Bruno (bru) |
CLI Apidog (apidog) |
|---|---|---|
| Package | @usebruno/cli |
apidog-cli |
| Commande d'exécution | bru run |
apidog run |
| Source du test | Fichiers .bru dans votre dépôt Git |
Scénarios de test dans votre projet Apidog, récupérés par ID |
| Création | Édition manuelle de fichiers texte ou utilisation de l'application Bruno | Constructeur de scénarios visuel dans l'application Apidog |
| Authentification en CI | Aucune ; s'exécute hors ligne | Jeton d'accès (--access-token) |
| Sélectionner ce qui s'exécute | Chemin du dossier, récursif -r, --tags |
Scénario -t, dossier -f, --test-suite |
| Environnement | --env <nom> |
-e <idEnvironnement> |
| Basé sur les données | --csv-file-path, --json-file-path |
-d <chemin> (CSV ou JSON) |
| Itérations | --iteration-count <n> |
-n <n> |
| Rapporteurs | JSON, JUnit, HTML | cli, html, json, junit |
| Échec rapide | --bail |
--on-error end (par défaut échoue à la première erreur) |
| Open source | Oui | Non (CLI npm gratuit ; exécute des scénarios de votre plan) |
| Licence/compte | Aucun pour le CLI | Compte Apidog pour le projet |
Deux choses ressortent. Premièrement, les deux exécuteurs couvrent les mêmes éléments essentiels de la CI : sélection d'environnement, itération basée sur les données, les trois formats de rapport importants et une sortie non nulle en cas d'échec. Deuxièmement, la distinction porte sur l'emplacement du test et la manière dont vous l'avez écrit, et non sur la capacité brute. Bruno conserve le test dans le dépôt sous forme de texte. Apidog le conserve dans le projet sous forme de scénario visuel et l'exécute par référence.
Rapporteurs et codes de sortie : les parties que la CI lit réellement
Un exécuteur gagne sa place dans un pipeline grâce à deux comportements : le rapport qu'il écrit et le code de sortie qu'il renvoie. Si ceux-ci sont corrects, le reste est une question de câblage.
Bruno écrit des rapports avec des drapeaux par format. Vous spécifiez un chemin pour chaque format que vous souhaitez :
bru run -r --env staging \
--reporter-junit ./results/junit.xml \
--reporter-html ./results/report.html \
--reporter-json ./results/report.json
Le XML JUnit est ce que votre tableau de bord CI analyse en un arbre de réussite/échec. Le rapport HTML est un artefact navigable. Le drapeau --bail de Bruno arrête l'exécution après la première requête, test ou assertion échouée, ce qui permet un feedback rapide sur un test de fumée. Sans --bail, il exécute tout et signale toutes les défaillances en même temps.
Apidog utilise un seul drapeau -r avec une liste séparée par des virgules, et écrit tout dans un seul répertoire de sortie :
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 \
-r html,junit --out-dir ./apidog-reports
Son drapeau --on-error façonne le comportement en cours de scénario : end s'arrête à la première défaillance (le défaut), continue exécute chaque étape afin que vous puissiez collecter toutes les défaillances dans un seul rapport, et ignore passe outre une étape connue pour être instable. Dans tous les cas, l'exécution se termine avec un code non nul si quelque chose a échoué.
Le contrat de code de sortie est le même des deux côtés et c'est la partie essentielle. Lorsqu'une assertion échoue, l'exécuteur se termine avec un code non nul. La CI lit ce code, marque l'étape comme échouée, fait échouer la tâche et bloque la fusion ou le déploiement. Vous n'avez rien à configurer en plus. Le seul piège, identique pour les deux, est d'ignorer le code de sortie : si vous enveloppez l'exécution dans un pipeline shell ou ajoutez || true, la sortie non nulle est annulée et la barrière cesse de fonctionner silencieusement. Ne faites pas cela.
Le CLI Bruno dans GitHub Actions
Étant donné que les fichiers .bru sont déjà dans le dépôt, le workflow est court. Récupérez le code, installez le CLI, exécutez la collection, téléchargez le rapport.
name: Tests API
on:
pull_request:
branches: [main]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- name: Récupération du code
uses: actions/checkout@v4
- name: Configuration de Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Installation du CLI Bruno
run: npm install -g @usebruno/cli
- name: Exécution des tests API
working-directory: ./api-tests
run: bru run -r --env staging --reporter-junit ./results/junit.xml
- name: Téléchargement du rapport
if: always()
uses: actions/upload-artifact@v4
with:
name: rapport-bruno
path: ./api-tests/results
Le working-directory pointe vers le dossier contenant votre collection. if: always() maintient le téléchargement du rapport même lorsque les tests échouent, ce qui est précisément le moment où vous voulez le lire. Aucun secret n'est nécessaire car rien ne s'authentifie auprès d'un service distant.
Le CLI Apidog dans GitHub Actions
Le workflow Apidog est structurellement le même, avec un ajout : le jeton d'accès provient des secrets du dépôt, et vous sélectionnez le scénario par ID au lieu du chemin du dossier.
name: Tests API
on:
pull_request:
branches: [main]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- name: Récupération du code
uses: actions/checkout@v4
- name: Configuration de Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Installation du CLI Apidog
run: npm install -g apidog-cli
- name: Exécution du scénario de test API
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t 605067 \
-e 1629989 \
-r html,junit \
--out-dir ./apidog-reports
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
- name: Téléchargement du rapport
if: always()
uses: actions/upload-artifact@v4
with:
name: rapport-apidog
path: ./apidog-reports
Remarquez la symétrie. Même extraction, même configuration Node, même forme d'installation-puis-exécution, même téléchargement systématique. Les seules vraies différences sont le jeton câblé en tant que secret et le scénario sélectionné par ID. Si vous voulez une version étendue avec des variantes GitLab CI et Jenkins, le guide complet du CLI Apidog applique le même modèle à travers les différents exécuteurs.
Comment choisir
La décision se résume rarement à savoir quel exécuteur est le "meilleur". Elle dépend de la manière dont votre équipe souhaite créer et stocker les tests.
Choisissez Bruno lorsque le dépôt est la source de vérité. Si vous voulez que chaque test soit un fichier texte brut vivant à côté du code qu'il couvre, examiné dans la même pull request, sans compte et sans appel réseau au moment de l'exécution, Bruno correspond exactement à ce modèle. C'est le choix naturel pour les équipes qui considèrent les tests comme du code, valorisent les outils hors ligne et open source, et sont à l'aise pour éditer directement les fichiers .bru. Bruno Ultimate ajoute le SSO, le SCIM, les intégrations de gestionnaires de secrets et les fonctionnalités d'audit si vous avez besoin par la suite de la couche d'équipe et de gouvernance, donc l'évolution est une option plutôt qu'un obstacle.
Choisissez Apidog lorsque la vitesse de création et un flux de travail intégré sont plus importants que le contrôle au niveau du fichier. Si vous préférez construire un scénario de test visuellement, enchaîner les requêtes, extraire des variables et exécuter le même scénario sur différents environnements sans écrire et déboguer manuellement le code de test, le modèle d'Apidog supprime cette friction. La conception, le débogage, le mocking et le test vivent dans un seul espace de travail, et le CLI exécute le scénario exact que vous avez construit. Pour les équipes venant d'une configuration Postman, le modèle mental correspond proprement, et le chemin de migration est celui qu'Apidog couvre en tant qu'alternative à Postman pour les tests d'API.
Il existe aussi une réponse "les deux outils". Certaines équipes conservent les fichiers Git-natifs de Bruno pour les vérifications de requêtes de bas niveau et utilisent Apidog pour les scénarios enchaînés plus complexes et les exécutions de régression lourdes en environnement. Les deux CLI coexistent parfaitement dans un seul pipeline ; ce sont des étapes distinctes avec des codes de sortie distincts.
Si vous avez dû choisir entre les plateformes de manière plus générale, et pas seulement les CLI, la comparaison Apidog vs Bruno couvre la conception, le mocking et la collaboration au-delà de la ligne de commande. Pour configurer votre premier scénario automatisé et l'exécuter depuis le terminal le même après-midi, téléchargez Apidog et copiez la commande générée depuis l'onglet CI/CD de n'importe quel scénario.
Foire aux questions
Le CLI Bruno est-il gratuit ?
Oui. Le CLI Bruno est open source et est distribué en tant que package npm @usebruno/cli. Il s'exécute entièrement sur votre machine ou votre exécuteur CI sans compte ni jeton. Bruno Ultimate est un niveau payant distinct qui ajoute des fonctionnalités d'équipe et de gouvernance comme le SSO, le SCIM, les intégrations de gestionnaires de secrets et l'audit, mais le CLI lui-même est gratuit.
Le CLI Apidog est-il gratuit ?
Le CLI est un package npm gratuit, apidog-cli. Il exécute les scénarios de test de votre projet Apidog, donc ce que vous pouvez exécuter dépend de votre plan Apidog, mais l'exécuteur en ligne de commande n'est pas un produit payant séparé.
Dois-je écrire des tests sous forme de code pour l'un ou l'autre des exécuteurs ?
Pour Bruno, vos tests sont des fichiers .bru que vous pouvez éditer manuellement ou créer dans l'application Bruno, il y a donc un format texte que vous toucherez directement. Pour Apidog, vous construisez des scénarios visuellement dans l'application et le CLI les exécute par ID, vous n'avez donc pas à maintenir le code de test à la main. C'est la principale différence de création entre les deux.
Les deux exécuteurs font-ils échouer la build lorsqu'un test échoue ?
Oui. Les deux se terminent avec un code non nul lorsqu'une assertion échoue, ce que la CI lit pour marquer l'étape comme échouée et bloquer la fusion ou le déploiement. Le --bail de Bruno s'arrête à la première défaillance ; le --on-error end d'Apidog fait de même et est le comportement par défaut. Évitez d'envelopper l'une ou l'autre exécution dans || true, ce qui annule le code de sortie et brise la barrière.
Quel format de rapport dois-je utiliser en CI ?
Utilisez le XML JUnit pour le résultat lisible par machine que votre tableau de bord CI analyse en un arbre de réussite/échec, et ajoutez du HTML si vous souhaitez un artefact navigable. Bruno les écrit avec --reporter-junit et --reporter-html ; Apidog utilise -r html,junit. Les deux supportent également le JSON pour un post-traitement personnalisé.
Le CLI Bruno a-t-il besoin d'une connexion internet ou d'un compte pour s'exécuter ?
Non. Bruno exécute les fichiers .bru de votre dépôt localement, sans connexion ni récupération à distance, ce qui le rend adapté aux CI hors ligne ou isolées (air-gapped). Le CLI d'Apidog s'authentifie avec un jeton d'accès et récupère le scénario de votre projet, il a donc besoin d'un accès réseau au service Apidog au moment de l'exécution.
Puis-je exécuter l'un ou l'autre des CLI sans installation globale ?
Oui pour les deux. Utilisez npx @usebruno/cli run ... ou npx apidog-cli run ... pour exécuter sans installation globale persistante, ce qui est pratique sur les exécuteurs CI éphémères. Exécutez bru run --help ou apidog run --help pour confirmer les options exactes disponibles dans votre version installée.
