惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
Simon Willison's Weblog
Simon Willison's Weblog
K
Kaspersky official blog
P
Palo Alto Networks Blog
Google DeepMind News
Google DeepMind News
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AI
AI
G
GRAHAM CLULEY
O
OpenAI News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Help Net Security
Help Net Security
L
LINUX DO - 热门话题
S
Schneier on Security
P
Privacy International News Feed
L
Lohrmann on Cybersecurity
SecWiki News
SecWiki News
C
Cybersecurity and Infrastructure Security Agency CISA
T
Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
A
Arctic Wolf
C
Cisco Blogs
V2EX - 技术
V2EX - 技术
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
Latest news
Latest news
人人都是产品经理
人人都是产品经理
Schneier on Security
Schneier on Security
Last Week in AI
Last Week in AI
Webroot Blog
Webroot Blog
美团技术团队
N
News and Events Feed by Topic
大猫的无限游戏
大猫的无限游戏
Security Archives - TechRepublic
Security Archives - TechRepublic
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
Project Zero
Project Zero
博客园_首页
Cloudbric
Cloudbric
IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
罗磊的独立博客
Hacker News: Ask HN
Hacker News: Ask HN
The Last Watchdog
The Last Watchdog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tenable Blog
Scott Helme
Scott Helme

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Bruno CLI vs Apidog CLI: Rodando Testes de API na CI
Lucas · 2026-06-15 · via DEV Community

Seus testes de API passam no seu laptop. O que importa é se eles rodam em cada pull request, merge e build noturno sem intervenção humana. Para isso, você precisa de um executor de linha de comando: ele roda os testes em modo headless dentro do pipeline, retorna código de saída correto e gera relatórios que o CI consegue ler.

Experimente o Apidog hoje

Dois CLIs aparecem com frequência nessa configuração: Bruno CLI e Apidog CLI. Ambos executam testes de API em CI/CD, mas partem de modelos diferentes:

  • Bruno é git-native, offline-first e open source. O CLI executa arquivos .bru versionados no repositório.
  • Apidog é uma plataforma de API completa. O CLI executa cenários visuais criados no aplicativo, buscados por ID.

Ambos funcionam em GitHub Actions, GitLab CI, Jenkins e qualquer runner com Node.js. Ambos falham a build quando um teste falha. A diferença principal está em como você cria os testes, onde eles ficam e como o CI os acessa.

Em resumo

  • Bruno CLI (@usebruno/cli, binário bru) executa arquivos .bru diretamente de uma pasta no seu repositório Git.
  • Apidog CLI (apidog-cli, binário apidog) executa cenários de teste visuais do seu projeto Apidog usando um access token.
  • Ambos geram relatórios JUnit, JSON e HTML.
  • Ambos retornam código de saída diferente de zero quando há falha.
  • Use Bruno quando quiser testes em texto simples, versionados no repositório, sem conta e sem dependência de rede.
  • Use Apidog quando quiser criar cenários visualmente, encadear requisições, reutilizar ambientes e rodar testes data-driven sem manter código de teste manualmente.

O problema: testes que existem, mas não rodam

Um teste executado só manualmente tende a ficar desatualizado. A API muda, o teste continua parado e ninguém percebe até quebrar algo em produção.

O objetivo do CLI é transformar esses testes em um gate automatizado:

  1. Rodar sem interface gráfica.
  2. Retornar erro quando uma asserção falhar.
  3. Gerar relatório para o CI.
  4. Permitir execução por ambiente, pasta, cenário ou tag.
  5. Funcionar em pipelines repetíveis.

Se você está montando a base de CI/CD para testes de API, também vale ler sobre automatização de testes de API em CI/CD. Aqui o foco é a comparação prática entre os dois CLIs.

O que o Bruno CLI faz bem

O Bruno foi desenhado para ser git-native. Requisições, ambientes e asserções ficam em arquivos .bru no disco, dentro do repositório.

Isso traz vantagens claras para times que tratam testes como código:

  • O teste muda no mesmo pull request que altera o endpoint.
  • O diff é revisável como qualquer arquivo de texto.
  • Você pode usar grep, refatorações, busca no editor e resolução normal de conflitos.
  • O CI não precisa buscar testes em um serviço externo.
  • Não há login, token ou conta para executar localmente.

Esse modelo também funciona bem em ambientes restritos ou air-gapped, porque o CLI executa localmente os arquivos do repositório.

Instale o Bruno CLI:

npm install -g @usebruno/cli

Execute uma coleção:

bru run --env staging

Se os testes estiverem em subpastas, use execução recursiva:

bru run -r --env staging

Exemplo de estrutura comum:

api-tests/
├── environments/
│   └── staging.bru
├── users/
│   ├── create-user.bru
│   └── get-user.bru
└── orders/
    └── create-order.bru

No CI, você aponta o comando para essa pasta. Os arquivos .bru são a fonte da verdade.

Para contexto mais amplo, veja também o que torna Bruno diferente como cliente de API git-native e onde suas limitações aparecem para equipes maiores.

O que o Apidog CLI faz bem

O Apidog usa outro modelo: você cria os testes visualmente no aplicativo e o CLI executa esses cenários em modo headless.

Um cenário pode incluir:

  • várias requisições encadeadas;
  • extração de valores da resposta;
  • uso de variáveis em etapas seguintes;
  • asserções;
  • ambientes;
  • execução com arquivo CSV ou JSON.

A vantagem é que você não mantém duas versões do mesmo teste. O cenário visual é o teste. O CLI apenas executa esse cenário no pipeline.

Instale o Apidog CLI:

npm install -g apidog-cli

Exemplo de execução:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -n 1 -r html,junit

Onde:

  • --access-token autentica o CLI.
  • -t 605067 seleciona o cenário de teste.
  • -e 1629989 seleciona o ambiente.
  • -n 1 define o número de iterações.
  • -r html,junit gera relatórios HTML e JUnit.

Na prática, você não precisa memorizar esses IDs. No Apidog:

  1. Abra o cenário de teste.
  2. Vá para a aba CI/CD.
  3. Gere um access token.
  4. Copie o comando gerado.
  5. Mova o token para um segredo do CI.
  6. Referencie o token como variável de ambiente.

A referência de opções está no guia completo do Apidog CLI.

Bruno CLI vs Apidog CLI

Dimensão Bruno CLI (bru) Apidog CLI (apidog)
Pacote @usebruno/cli apidog-cli
Comando bru run apidog run
Fonte do teste Arquivos .bru no repositório Cenários no projeto Apidog
Autoria Arquivos de texto ou app Bruno Construtor visual no Apidog
Autenticação no CI Nenhuma --access-token
Seleção de testes Pasta, -r, --tags -t, -f, --test-suite
Ambiente --env <name> -e <environmentId>
Dados externos --csv-file-path, --json-file-path -d <path>
Iterações --iteration-count <n> -n <n>
Relatórios JSON, JUnit, HTML cli, html, json, junit
Falha rápida --bail --on-error end
Open source Sim Não; CLI npm gratuito
Conta necessária Não Sim, para acessar o projeto Apidog

A comparação prática é simples:

  • Bruno lê testes do disco.
  • Apidog busca testes do projeto.
  • Bruno favorece controle por Git.
  • Apidog favorece autoria visual e fluxo integrado.
  • Ambos cobrem os requisitos básicos de CI.

Relatórios e códigos de saída

No CI, duas coisas importam mais que a interface da ferramenta:

  1. O relatório gerado.
  2. O código de saída do comando.

Bruno: gerar JUnit, HTML e JSON

bru run -r --env staging \
  --reporter-junit ./results/junit.xml \
  --reporter-html ./results/report.html \
  --reporter-json ./results/report.json

Use:

  • --reporter-junit para o painel do CI.
  • --reporter-html para um artefato navegável.
  • --reporter-json para pós-processamento.
  • --bail para parar na primeira falha.

Exemplo com falha rápida:

bru run -r --env staging \
  --bail \
  --reporter-junit ./results/junit.xml

Apidog: gerar relatórios em um diretório

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 \
  -r html,junit \
  --out-dir ./apidog-reports

Controle de erro:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 \
  --on-error continue \
  -r html,junit \
  --out-dir ./apidog-reports

Opções úteis:

  • --on-error end: para na primeira falha.
  • --on-error continue: continua e coleta todas as falhas.
  • --on-error ignore: ignora erros de etapas específicas conforme configuração.

Em ambos os casos, se uma asserção falhar, o processo termina com código diferente de zero. O CI usa esse código para falhar o job.

Evite isto:

bru run -r --env staging || true

Ou isto:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 || true

Esse padrão engole o erro e quebra o gate de qualidade.

Bruno CLI no GitHub Actions

Como os arquivos .bru estão no repositório, o workflow é direto:

name: Testes de API

on:
  pull_request:
    branches: [main]

jobs:
  api-tests:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Instalar Bruno CLI
        run: npm install -g @usebruno/cli

      - name: Executar testes de API
        working-directory: ./api-tests
        run: |
          bru run -r \
            --env staging \
            --reporter-junit ./results/junit.xml \
            --reporter-html ./results/report.html

      - name: Fazer upload dos relatórios
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: relatorio-bruno
          path: ./api-tests/results

Pontos importantes:

  • working-directory deve apontar para a pasta da coleção.
  • if: always() garante upload do relatório mesmo quando o teste falha.
  • Nenhum segredo é necessário para executar o CLI.

Apidog CLI no GitHub Actions

No Apidog, o workflow é parecido, mas usa um segredo para o token:

name: Testes de API

on:
  pull_request:
    branches: [main]

jobs:
  api-tests:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Instalar Apidog CLI
        run: npm install -g apidog-cli

      - name: Executar cenário de teste de 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: Fazer upload dos relatórios
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: relatorio-apidog
          path: ./apidog-reports

Checklist para configurar:

  1. Gere o comando na aba CI/CD do cenário.
  2. Crie o segredo APIDOG_ACCESS_TOKEN no GitHub.
  3. Cole o ID do cenário em -t.
  4. Cole o ID do ambiente em -e.
  5. Publique os relatórios com actions/upload-artifact.

Para exemplos em outros CIs, veja o guia completo do Apidog CLI.

Execução sem instalação global

Em runners efêmeros, você pode usar npx.

Bruno:

npx @usebruno/cli run -r --env staging

Apidog:

npx apidog-cli run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t 605067 \
  -e 1629989

Isso evita instalação global persistente no runner.

Como escolher

A escolha não é apenas “qual CLI é melhor”. É qual modelo combina com seu time.

Escolha Bruno se você quer testes como código

Bruno faz sentido quando:

  • o repositório é a fonte da verdade;
  • os testes devem ser revisados no mesmo PR do código;
  • você quer arquivos de texto simples;
  • o CI precisa funcionar sem conta externa;
  • o time prefere ferramentas open source e offline;
  • você aceita editar ou manter arquivos .bru.

É uma boa opção para times que querem controle total no Git e previsibilidade em ambientes restritos.

Escolha Apidog se você quer autoria visual e fluxo integrado

Apidog faz sentido quando:

  • o time prefere criar cenários visualmente;
  • você quer encadear requisições sem escrever scripts manuais;
  • os mesmos cenários devem rodar em vários ambientes;
  • testes, documentação, mock e depuração vivem no mesmo workspace;
  • você quer gerar o comando de CI a partir da interface;
  • o time vem de ferramentas como Postman.

Nesse caso, o CLI vira apenas o executor headless do cenário já modelado visualmente.

Se você está avaliando alternativas ao Postman, veja também a comparação do Apidog como alternativa ao Postman para testes de API.

Você também pode usar os dois

Alguns times combinam os dois modelos:

  • Bruno para checks pequenos, rápidos e versionados junto ao código.
  • Apidog para cenários encadeados, regressão e testes orientados a dados.

No pipeline, eles são apenas etapas separadas:

- name: Rodar testes Bruno
  run: bru run -r --env staging

- name: Rodar cenários Apidog
  run: |
    apidog run \
      --access-token "$APIDOG_ACCESS_TOKEN" \
      -t 605067 \
      -e 1629989

Se qualquer etapa retornar erro, o job falha.

Para uma comparação mais ampla entre as plataformas, incluindo design, mocking e colaboração, veja Apidog vs Bruno.

Perguntas frequentes

O Bruno CLI é gratuito?

Sim. O Bruno CLI é open source e distribuído como o pacote npm @usebruno/cli. Ele executa localmente, sem conta ou token. O Bruno Ultimate é um nível pago separado com recursos de equipe e governança, como SSO, SCIM, integrações com gerenciadores de segredos e auditoria.

O Apidog CLI é gratuito?

O CLI é um pacote npm gratuito, apidog-cli. Ele executa cenários do seu projeto Apidog, então o que você pode executar depende do seu plano Apidog. O runner de linha de comando não é um produto pago separado.

Preciso escrever testes como código?

Depende da ferramenta.

No Bruno, os testes são arquivos .bru, que você pode editar diretamente ou criar pelo aplicativo Bruno.

No Apidog, você cria cenários visualmente no aplicativo e o CLI executa esses cenários por ID. Você não mantém manualmente arquivos de teste como código.

Ambos falham a build quando um teste falha?

Sim. Ambos retornam código de saída diferente de zero quando uma asserção falha. O CI usa esse código para marcar o job como falho e bloquear merge ou deploy.

Qual formato de relatório devo usar no CI?

Use JUnit XML para integração com painéis de CI. Use HTML como artefato navegável para depuração.

Bruno:

bru run -r --env staging \
  --reporter-junit ./results/junit.xml \
  --reporter-html ./results/report.html

Apidog:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 \
  -r html,junit \
  --out-dir ./apidog-reports

O Bruno CLI precisa de internet?

Não para executar testes locais. Ele lê os arquivos .bru do repositório e roda sem login ou busca remota.

O Apidog CLI precisa de internet?

Sim. Ele autentica com um access token e busca o cenário no projeto Apidog, então precisa de acesso à rede ao serviço Apidog durante a execução.

Posso rodar os CLIs localmente antes de configurar o CI?

Sim.

Bruno:

bru run -r --env staging

Apidog:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989

Antes de colocar no pipeline, confirme que o comando local retorna erro quando uma asserção falha. Esse comportamento é o que vai proteger seu merge no CI.