Bruno CLI vs Apidog CLI: Rodando Testes de API na CI

Bruno CLI vs Apidog CLI comparados para CI: comandos de instalação, flags, reporters, códigos de saída e exemplos para GitHub Actions para ajudar você a escolher o executor de testes de API certo.

Ashley Innocent

Ashley Innocent

15 junho 2026

Bruno CLI vs Apidog CLI: Rodando Testes de API na CI

Apidog para empresas

Implantação local

SSO & RBAC

Conforme SOC 2

Explorar Apidog Enterprise

Seus testes de API são aprovados no seu laptop. A verdadeira questão é se eles são executados em cada pull request, cada merge, cada build noturno, sem que um humano clique em nada. Essa tarefa pertence a um executor de linha de comando. Ele pega os testes que você já criou e os executa de forma *headless* dentro do seu *pipeline*, sai com um código de status limpo e escreve um relatório que seu painel de CI pode ler.

Dois *runners* (executores) surgem constantemente quando as equipes configuram isso: o Bruno CLI e o Apidog CLI. Eles resolvem o mesmo problema a partir de pontos de partida diferentes. Bruno é um cliente de API *git-native*, *offline-first* e de código aberto, e seu CLI executa os arquivos .bru que residem no seu repositório. Apidog é uma plataforma de API completa, e seu CLI executa os cenários de teste visuais que você constrói no aplicativo. Ambos se integram ao GitHub Actions, GitLab CI, Jenkins e qualquer outra coisa com Node.js. Ambos falham a *build* quando um teste falha. As diferenças aparecem em como você cria os testes, como você se autentica e como a definição do teste viaja para o CI.

botão

Esta é uma comparação honesta, em nível de comando, dos dois. Sem *strawmen* (argumentos de espantalho). Bruno faz várias coisas genuinamente bem, e você verá exatamente onde cada *runner* se encaixa antes de conectá-lo ao seu *pipeline*.

EM RESUMO

O problema real: testes que existem mas nunca são executados

Um teste que você executa manualmente é um teste que apodrece. Alguém o construiu, ele passou uma vez, e então permaneceu intocado enquanto a API mudava por baixo dele. A solução não é mais testes. São testes que são executados automaticamente a cada mudança, com um sinal de passa/falha que o *pipeline* pode usar.

Um *runner* CLI é o que fecha essa lacuna. Ele precisa de três coisas para ser útil no CI: ele deve ser executado sem uma GUI, deve sair com um código diferente de zero quando algo falha para que a *build* fique vermelha, e deve escrever um relatório legível por máquina para que os revisores vejam o que quebrou. Bruno e Apidog ambos atingem esse nível. Onde eles diferem é antes do comando de execução, em como o teste foi escrito e onde ele reside.

Se você está configurando o CI do zero, os padrões mais amplos em automatização de testes de API em CI/CD valem a pena ser lidos junto com esta comparação. Aqui nos concentramos nos dois *runners* em si.

O que o Bruno CLI faz bem

Todo o design do Bruno é *git-native*. Cada requisição, ambiente e asserção é um arquivo .bru em texto simples no disco, dentro do seu repositório, versionado como qualquer outro arquivo-fonte. Esse modelo tem vantagens reais, e vale a pena declará-las claramente antes de qualquer comparação.

Seus testes vivem com seu código. Um *pull request* que altera um *endpoint* pode mudar o teste para aquele *endpoint* no mesmo *diff*, revisado pela mesma pessoa. Não há um sistema separado para sincronizar, nenhuma cópia na nuvem que possa se desviar do que está no repositório. Os *diffs* são legíveis porque o formato é texto. Você pode *grep* seus testes, refatorá-los com as mesmas ferramentas que usa para código e resolver conflitos de *merge* em um editor.

Também é de código aberto e *offline*. O CLI é executado inteiramente na sua máquina ou no seu *runner* de CI sem conta, login e token. Para equipes com regras rígidas de manuseio de dados ou ambientes isolados (*air-gapped*), isso importa. O nível pago do Bruno, Bruno Ultimate, adiciona recursos de equipe, incluindo SSO e SCIM, integrações com gerenciadores de segredos e recursos de auditoria, então o projeto não é apenas uma ferramenta para *hobbystas*. Mas o cliente principal e o CLI são gratuitos e autônomos, e essa é uma força legítima.

A instalação é um único comando:

npm install -g @usebruno/cli

O binário é bru. Você executa uma coleção apontando-o para a pasta que contém seus arquivos .bru:

bru run --env staging

Execute de dentro do diretório da coleção e bru run executa as requisições que encontra lá. Adicione -r para percorrer subpastas e assim ele encontra requisições aninhadas:

bru run -r --env staging

Esse é o *loop* principal. Sem IDs, sem token, sem *remote fetch*. Os arquivos na pasta são os testes, e o CLI os executa.

Abordamos a história mais ampla do Bruno em o que torna Bruno diferente como cliente de API git-native e onde suas limitações aparecem para equipes maiores. Para o CI especificamente, as forças acima são as que contam.

O que o Apidog CLI faz bem

Apidog segue um caminho diferente para o mesmo *pipeline*. Você constrói testes visualmente no aplicativo Apidog: encadeia requisições em um cenário, adiciona asserções, extrai um valor de uma resposta para a próxima requisição e repete todo o processo sobre um arquivo de dados. O CLI é o executor *headless* para esses cenários. Ele não tem seu próprio formato de arquivo. Ele busca o cenário que você nomeia por ID do seu projeto Apidog e o executa exatamente como o aplicativo faria.

A vantagem é que ninguém mantém duas representações do mesmo teste. O cenário no projeto é o teste. Você o cria em um construtor visual que lida com encadeamento de requisições, extração de variáveis e asserções sem que você precise escrever e depurar arquivos de *script*. Então o CLI executa esse mesmo cenário no CI. O *loop* de autoria rápida e o *loop* de automação usam uma única fonte de verdade.

A instalação é um único comando npm:

npm install -g apidog-cli

O binário é apidog. Uma execução típica nomeia um cenário por ID, escolhe um ambiente e se autentica com um *access token*:

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

Você não digita esses IDs manualmente. Abra o cenário de teste, mude para sua aba CI/CD, gere um *access token*, e o Apidog constrói o comando completo para você com o ID do cenário e o ID do ambiente já preenchidos. Você o copia uma vez, então move o token para um segredo de CI e o referencia como $APIDOG_ACCESS_TOKEN. A referência completa de *flags* está no guia completo do Apidog CLI se você quiser todas as opções em um só lugar.

O modelo baseado em token é a diferença mais clara em relação ao Bruno. O Apidog executa testes armazenados em um projeto que o CLI acessa pela rede, autenticado. O Bruno executa testes armazenados como arquivos que o CLI lê do disco. Nenhum está errado; eles se adequam a diferentes configurações de equipe.

Lado a lado

Dimensão Bruno CLI (bru) Apidog CLI (apidog)
Pacote @usebruno/cli apidog-cli
Comando de execução bru run apidog run
Fonte do teste Arquivos .bru no seu repositório git Cenários de teste no seu projeto Apidog, buscados por ID
Autoria Edição manual de arquivos de texto ou uso do aplicativo Bruno Construtor de cenário visual no aplicativo Apidog
Autenticação no CI Nenhuma; executado offline Access token (--access-token)
Selecionar o que será executado Caminho da pasta, -r recursivo, --tags -t cenário, -f pasta, --test-suite
Ambiente --env <name> -e <environmentId>
Orientado a dados --csv-file-path, --json-file-path -d <path> (CSV ou JSON)
Iterações --iteration-count <n> -n <n>
Geradores de relatórios JSON, JUnit, HTML cli, html, json, junit
Falha rápida --bail --on-error end (o padrão falha no primeiro erro)
Código aberto Sim Não (CLI npm gratuito; executa cenários do seu plano)
Licença/conta Nenhuma para o CLI Conta Apidog para o projeto

Duas coisas se destacam. Primeiro, ambos os *runners* cobrem os mesmos essenciais do CI: seleção de ambiente, iteração orientada a dados, os três formatos de relatório importantes e uma saída diferente de zero em caso de falha. Segundo, a divisão é sobre onde o teste reside e como você o escreveu, não sobre capacidade bruta. Bruno mantém o teste no repositório como texto. Apidog o mantém no projeto como um cenário visual e o executa por referência.

Geradores de relatórios e códigos de saída: as partes que o CI realmente lê

Um *runner* ganha seu lugar em um *pipeline* por meio de dois comportamentos: o relatório que ele escreve e o código de saída que ele retorna. Acertando isso, o resto é fiação.

Bruno escreve relatórios com *flags* por formato. Você passa um caminho para cada formato desejado:

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

O JUnit XML é o que seu painel de CI analisa em uma árvore de aprovação/reprovação. O relatório HTML é um artefato navegável. O --bail do Bruno interrompe a execução após a primeira requisição, teste ou asserção falha, o que mantém o feedback rápido em um teste de fumaça (*smoke test*). Sem --bail, ele executa tudo e relata todas as falhas de uma vez.

Apidog usa uma única *flag* -r com uma lista separada por vírgulas, e escreve tudo em um único diretório de saída:

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

Sua *flag* --on-error molda o comportamento no meio do cenário: end para na primeira falha (o padrão), continue executa cada passo para que você colete todas as falhas em um relatório, e ignore pula um passo conhecido por ser instável (*flaky*). De qualquer forma, a execução termina com um código diferente de zero se algo falhou.

O contrato do código de saída é o mesmo em ambos os lados e é a parte fundamental. Quando uma asserção falha, o *runner* sai com um código diferente de zero. O CI lê esse código, marca o passo como falho, falha o *job* e bloqueia o *merge* ou o *deploy*. Você não configura nada extra. A única armadilha, idêntica para ambos, é engolir o código de saída: se você envolver a execução em um *shell pipeline* ou adicionar || true, a saída diferente de zero é "comida" e o *gate* para de funcionar silenciosamente. Não faça isso.

Bruno CLI no GitHub Actions

Como os arquivos .bru já estão no repositório, o *workflow* é curto. Faça o *checkout* do código, instale o CLI, execute a coleção, faça o *upload* do relatório.

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

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

O working-directory aponta para a pasta que contém sua coleção. if: always() mantém o *upload* do relatório em execução mesmo quando os testes falham, que é exatamente quando você quer lê-lo. Nenhum segredo é necessário porque nada se autentica a um serviço remoto.

Apidog CLI no GitHub Actions

O *workflow* do Apidog é estruturalmente o mesmo, com uma adição: o *access token* vem de segredos do repositório, e você seleciona o cenário por ID em vez de por caminho da pasta.

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 do relatório
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: relatorio-apidog
          path: ./apidog-reports

Note a simetria. Mesmo *checkout*, mesma configuração de Node, mesmo formato instalar-e-executar, mesmo *upload* sempre. As únicas diferenças reais são o token configurado como um segredo e o cenário selecionado por ID. Se você quiser isso expandido com variantes para GitLab CI e Jenkins também, o guia completo do Apidog CLI mantém o mesmo padrão entre os *runners*.

Como escolher

A decisão raramente se resume a qual *runner* é "melhor". Ela se resume a como sua equipe deseja criar e armazenar os testes.

Escolha Bruno quando o repositório é a fonte da verdade. Se você quer cada teste como um arquivo de texto simples vivendo ao lado do código que ele cobre, revisado no mesmo *pull request*, sem conta e sem chamada de rede em tempo de execução, Bruno se encaixa exatamente nesse modelo. É a escolha natural para equipes que tratam testes como código, valorizam ferramentas *offline* e de código aberto, e se sentem à vontade para editar arquivos .bru diretamente. Bruno Ultimate adiciona recursos de SSO, SCIM, integrações com gerenciadores de segredos e auditoria se você precisar mais tarde da camada de equipe e governança, então crescer com ele é uma opção em vez de uma barreira.

Escolha Apidog quando a velocidade de autoria e um *workflow* integrado importam mais do que o controle em nível de arquivo. Se você prefere construir um cenário de teste visualmente, encadear requisições, extrair variáveis e executar o mesmo cenário em vários ambientes sem escrever e depurar código de teste manualmente, o modelo do Apidog remove essa fricção. Design, depuração, *mock* e teste vivem em um único espaço de trabalho, e o CLI executa o cenário exato que você construiu. Para equipes vindo de uma configuração Postman, o modelo mental se alinha de forma limpa, e o caminho de migração é um que o Apidog cobre como uma alternativa ao Postman para testes de API.

Há também uma resposta para ambas as ferramentas. Algumas equipes mantêm os arquivos *git-native* do Bruno para verificações de requisição de baixo nível e usam o Apidog para os cenários encadeados maiores e execuções de regressão com muitos ambientes. Os dois CLIs coexistem bem em um *pipeline*; são passos separados com códigos de saída separados.

Se você tem estado a decidir entre as plataformas de forma mais ampla, não apenas os CLIs, a comparação Apidog vs Bruno cobre design, *mocking* e colaboração além da linha de comando. Para configurar seu primeiro cenário automatizado e executá-lo a partir do terminal na mesma tarde, baixe o Apidog e copie o comando gerado da aba CI/CD de qualquer cenário.

botão

Perguntas frequentes

O Bruno CLI é gratuito?

Sim. O Bruno CLI é de código aberto e é distribuído como o pacote npm @usebruno/cli. Ele é executado inteiramente na sua máquina ou *runner* de CI sem conta ou token. Bruno Ultimate é um nível pago separado que adiciona recursos de equipe e governança como SSO, SCIM, integrações com gerenciadores de segredos e auditoria, mas o CLI em si é gratuito.

O Apidog CLI é gratuito?

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

Preciso escrever testes como código para algum dos runners?

Para o Bruno, seus testes são arquivos .bru que você pode editar manualmente ou criar no aplicativo Bruno, então há um formato de texto que você irá manipular diretamente. Para o Apidog, você constrói cenários visualmente no aplicativo e o CLI os executa por ID, então você não mantém código de teste manualmente. Essa é a principal diferença de autoria entre os dois.

Ambos os runners falham a build quando um teste falha?

Sim. Ambos saem com um código diferente de zero quando uma asserção falha, o que o CI lê para marcar o passo como falho e bloquear o *merge* ou *deploy*. O --bail do Bruno para na primeira falha; o --on-error end do Apidog faz o mesmo e é o padrão. Evite envolver qualquer uma das execuções em || true, o que engole o código de saída e quebra o *gate*.

Qual formato de relatório devo usar no CI?

Use JUnit XML para o resultado legível por máquina que seu painel de CI analisa em uma árvore de aprovação/reprovação, e adicione HTML se você quiser um artefato navegável. Bruno os escreve com --reporter-junit e --reporter-html; Apidog usa -r html,junit. Ambos também suportam JSON para pós-processamento personalizado.

O Bruno CLI precisa de conexão com a internet ou conta para ser executado?

Não. Bruno executa os arquivos .bru do seu repositório localmente, sem login e sem *remote fetch*, o que o torna adequado para CI *offline* ou *air-gapped*. O CLI do Apidog se autentica com um *access token* e busca o cenário do seu projeto, então ele precisa de acesso à rede para o serviço Apidog em tempo de execução.

Posso executar qualquer um dos CLIs sem uma instalação global?

Sim para ambos. Use npx @usebruno/cli run ... ou npx apidog-cli run ... para executar sem uma instalação global persistente, o que é conveniente em *runners* de CI efêmeros. Execute bru run --help ou apidog run --help para confirmar as opções exatas disponíveis na sua versão instalada.

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs