cargo-nextest 2026: Testes Rust Mais Rápidos | Rust Brasil

Aprenda a usar cargo-nextest em projetos Rust: instalação, filtros, retries, perfis de CI, JUnit, testes lentos e migração segura do cargo test na CI.

O cargo-nextest é a escolha mais prática para executar suítes Rust grandes com melhor isolamento, paralelismo, filtros e relatórios de CI. Instale com cargo install cargo-nextest --locked, rode cargo nextest run na raiz do projeto e mantenha cargo test --doc se a base possui doctests. A migração deve ser gradual: compare a seleção e os resultados dos dois runners antes de trocar o comando obrigatório do pipeline.

O nextest não torna um teste individual magicamente mais rápido. O ganho vem da forma como a suíte é organizada e executada: cada teste roda em seu próprio processo, o scheduler distribui trabalho entre CPUs, falhas ficam isoladas e a configuração permite tratar testes lentos, retries e geração de relatórios sem encher o workflow de shell.

Este guia mostra como usar cargo-nextest em 2026 no computador e na CI, com filtros, perfis, JUnit, timeouts e uma estratégia segura para sair do cargo test. Se você ainda está estruturando a qualidade do projeto, comece pelo guia de testes em Rust e consulte também as ferramentas essenciais do Cargo.

O que é cargo-nextest

O Cargo já oferece um runner integrado por meio de cargo test. Ele compila os targets de teste, encontra funções marcadas com #[test] e executa os binários gerados. Para muitos projetos, isso é suficiente e continua sendo o ponto de partida correto.

O cargo-nextest trabalha sobre os artefatos de teste produzidos pelo Cargo, mas substitui a etapa de execução por um runner especializado. Entre os recursos mais úteis estão:

  • execução de cada teste em um processo separado;
  • agendamento paralelo da suíte;
  • filtros por nome, pacote, binário e plataforma;
  • retries configuráveis para casos realmente transitórios;
  • detecção e encerramento de testes lentos;
  • perfis diferentes para desenvolvimento e CI;
  • geração de relatório JUnit;
  • saída que destaca falhas sem misturar todo o log da suíte;
  • particionamento da execução para pipelines distribuídos.

O isolamento por processo merece atenção. Se um teste aborta, vaza estado global ou interfere no ambiente, a falha tende a ficar contida naquele processo. Isso não elimina problemas de concorrência em recursos compartilhados — banco, porta TCP, arquivo temporário ou serviço externo —, mas reduz o acoplamento existente quando vários testes vivem no mesmo processo.

cargo test vs cargo nextest

A decisão não precisa ser ideológica. Use cada ferramenta pelo papel que resolve melhor.

Critériocargo testcargo nextest
DisponibilidadeIncluído no CargoInstalação adicional
Execução padrãoRunner oficial do RustRunner especializado
IsolamentoTestes do binário compartilham processoUm processo por teste
FiltrosNome e opções do test harnessExpressões por teste, pacote, binário e plataforma
RetriesExigem lógica externaConfiguráveis por perfil e override
JUnitExige ferramenta complementarSuporte de relatório pelo perfil
DoctestsExecutados por cargo test --docDevem ser tratados separadamente no fluxo comum
Melhor encaixeProjetos simples e compatibilidade universalWorkspaces, suítes grandes e CI estruturada

A diferença mais importante é operacional. cargo test está disponível em qualquer instalação padrão e deve continuar passando. O nextest melhora a experiência de execução, principalmente quando o projeto tem muitos crates, testes de integração ou necessidade de relatórios consumidos pelo servidor de CI.

Como instalar cargo-nextest

Quem já instalou Rust pelo rustup pode compilar a ferramenta a partir do ecossistema Cargo:

cargo install cargo-nextest --locked
cargo nextest --version

--locked pede que a instalação respeite o lockfile publicado pelo pacote. Em máquinas de desenvolvimento isso oferece um caminho simples, embora a compilação inicial possa demorar.

Em CI, compilar a ferramenta em todo job desperdiça tempo. Prefira uma ação ou instalador dedicado, um cache confiável ou uma imagem interna que fixe a versão esperada. O objetivo é evitar que o runner mude sem revisão e, ao mesmo tempo, não transformar cada pipeline em uma compilação de ferramenta.

Depois da instalação, entre em um projeto Rust:

cargo nextest list
cargo nextest run

O primeiro comando lista o conjunto descoberto. O segundo compila o necessário e executa a suíte. Em um workspace, o nextest usa os metadados do Cargo para reconhecer packages e targets.

Primeiro fluxo recomendado

Antes de alterar a CI, estabeleça uma linha de base:

cargo test --workspace
cargo nextest list
cargo nextest run --workspace
cargo test --doc --workspace

Compare:

  1. quais packages foram compilados;
  2. quantos testes foram selecionados;
  3. quais variáveis de ambiente são necessárias;
  4. se algum teste depende de ordem ou estado global;
  5. se existem doctests relevantes;
  6. se a suíte abre portas ou compartilha banco de dados;
  7. se o resultado é igual em execução local e na CI.

Um teste que passa somente porque outro rodou antes possui dependência implícita. A execução isolada do nextest costuma revelar esse tipo de fragilidade. Corrija o setup do teste em vez de forçar uma ordem global.

Como executar um teste específico

Para uma busca rápida por nome, use uma expressão test():

cargo nextest run -E 'test(login_com_token_expirado)'

Confira a seleção antes de gastar tempo com a execução:

cargo nextest list -E 'test(login_com_token_expirado)'

Também é possível selecionar um package:

cargo nextest run -E 'package(api)'

Ou combinar critérios:

cargo nextest run -E 'package(api) and test(auth)'

Para excluir uma parte conhecida da suíte:

cargo nextest run -E 'not test(e2e_)'

As expressões são mais precisas do que encadear vários grep no pipeline. Elas também ajudam a documentar a intenção: “testes do package API relacionados a autenticação” é uma seleção compreensível por quem revisa o workflow.

Os nomes e predicados disponíveis devem ser conferidos na versão instalada, especialmente quando o filtro depende de plataforma, binário ou tipo de target. Use cargo nextest list como verificação, não apenas como comando de curiosidade.

Configurando .config/nextest.toml

A configuração do projeto fica normalmente em .config/nextest.toml. Um ponto de partida para CI:

[profile.ci]
retries = 0
fail-fast = false
slow-timeout = { period = "60s", terminate-after = 2 }

[profile.ci.junit]
path = "target/nextest/ci/junit.xml"

A execução passa a informar o perfil:

cargo nextest run --profile ci

Esse exemplo toma decisões conservadoras:

  • sem retries globais, para não esconder falhas reais;
  • fail-fast desativado, para coletar mais falhas em uma única rodada;
  • um teste que ultrapassa o período é marcado como lento e pode ser encerrado após repetições do limite;
  • o relatório JUnit é salvo dentro de target/nextest/.

No desenvolvimento local, o perfil padrão pode continuar mais simples:

cargo nextest run

Evite copiar uma configuração enorme antes de entender a suíte. Comece com um perfil de CI, observe os problemas e adicione overrides somente para categorias que realmente exigem tratamento diferente.

Retries sem esconder testes flaky

Retry é útil quando a falha é transitória e a equipe já entende sua causa: uma integração controlada pode sofrer uma indisponibilidade curta, por exemplo. Ele é perigoso quando vira maquiagem para teste não determinístico.

Uma política saudável:

  1. mantenha retries = 0 como padrão;
  2. identifique o teste flaky e abra uma correção;
  3. aplique retry somente ao conjunto necessário;
  4. registre a tentativa repetida nos artefatos da CI;
  5. remova a exceção quando a causa for corrigida.

Um override conceitual pode selecionar testes por expressão e mudar o comportamento apenas para eles:

[[profile.ci.overrides]]
filter = 'test(integracao_servico_legado)'
retries = 2

Valide a sintaxe com a versão usada no projeto. Mais importante: nunca use dezenas de tentativas para transformar instabilidade em “verde”. O pipeline perde credibilidade quando uma regressão pode falhar várias vezes e ainda ser aceita.

Para técnicas que ajudam a encontrar entradas inesperadas de forma determinística, veja property-based testing e fuzzing em Rust.

Testes lentos, timeouts e concorrência

Uma suíte pode ficar presa por deadlock, espera de rede, processo filho ou timeout ausente. O slow-timeout torna esse comportamento visível e permite encerrar testes que ultrapassam a política do projeto.

Antes de reduzir o limite agressivamente, meça. Um teste de integração que sobe PostgreSQL e executa migrações possui custo diferente de um teste unitário de parser. O ideal é separar categorias e criar infraestrutura previsível.

Se vários testes usam o mesmo recurso, considere:

  • um banco ou schema independente por teste;
  • portas dinâmicas em vez de números fixos;
  • diretórios criados com bibliotecas de arquivos temporários;
  • fixtures imutáveis;
  • locks apenas ao redor do recurso que não pode ser isolado;
  • redução intencional da concorrência para um grupo específico.

Não confunda “o runner executa em paralelo” com “todos os testes devem acessar a mesma instância simultaneamente”. A suíte precisa declarar e controlar seus recursos.

cargo-nextest no GitHub Actions

Um job enxuto pode instalar a toolchain, o nextest e executar os perfis do projeto:

name: Testes Rust

on:
  push:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - uses: taiki-e/install-action@nextest

      - name: Executar suíte
        run: cargo nextest run --workspace --profile ci

      - name: Executar doctests
        run: cargo test --doc --workspace

      - name: Publicar relatório
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: nextest-junit
          path: target/nextest/ci/junit.xml

A etapa if: always() preserva o relatório mesmo quando um teste falha. Isso facilita investigar a causa pelo artefato da execução.

Fixe versões de actions conforme a política de segurança da organização. Em ambientes mais rigorosos, use hashes de commit auditados em vez de somente tags. O guia de CI/CD para Rust cobre também formatação, Clippy, cache e builds para diferentes targets.

Como usar na Gitea Actions e em outras CIs

O conceito não depende do GitHub Actions. Em Gitea Actions, GitLab CI, Jenkins ou outro executor Linux, você precisa de quatro passos:

  1. disponibilizar a toolchain Rust;
  2. restaurar caches adequados;
  3. instalar uma versão conhecida do nextest;
  4. executar cargo nextest run --profile ci e guardar os relatórios.

Um shell genérico seria:

set -euo pipefail
cargo nextest --version
cargo nextest run --workspace --profile ci
cargo test --doc --workspace

O comando de instalação deve ficar na preparação da imagem ou em etapa cacheada. Não baixe um binário sem verificar origem, versão e integridade. Ferramentas de teste também fazem parte da segurança da cadeia de dependências Rust.

Particionando uma suíte grande

Quando um único runner não é suficiente, o nextest pode participar de uma estratégia de particionamento. A ideia é distribuir conjuntos diferentes de testes entre jobs, sem simplesmente executar a suíte inteira várias vezes.

Existem duas abordagens comuns:

  • por package ou domínio: API, worker, biblioteca e testes end-to-end em jobs separados;
  • por partição calculada: o runner divide a lista para diferentes índices do matrix.

Antes de distribuir, reduza o custo de compilação. Vários jobs podem repetir o mesmo build e consumir mais tempo total do que um job maior. Cache, artefatos compilados, arquitetura do workspace e duração de cada teste influenciam a decisão.

Para a maioria dos projetos, comece com um único job paralelo. Particione somente quando os dados da CI mostrarem que a etapa de execução — e não a compilação — domina o tempo.

Armadilhas comuns na migração

Esquecer os doctests

Se o projeto usa exemplos em documentação como testes, mantenha:

cargo test --doc --workspace

Uma pipeline que troca cargo test por nextest sem revisar doctests pode deixar de validar exemplos públicos da biblioteca.

Testes dependentes de ordem

A ordem não deve preparar estado para o teste seguinte. Cada teste precisa criar e limpar sua fixture ou usar dados isolados.

Estado compartilhado no sistema operacional

Variáveis de ambiente, diretório atual, portas e arquivos podem gerar disputa. O processo separado não resolve um banco compartilhado com a mesma chave primária.

Retries globais

Aplicar retries a toda a suíte aumenta custo e mascara regressões. Restrinja exceções e acompanhe-as como dívida técnica.

Instalação flutuante na CI

Instalar “a versão mais recente” em cada execução pode mudar o pipeline sem alteração no repositório. Fixe a versão ou controle a imagem usada.

Filtros que não selecionam o esperado

Sempre confira com cargo nextest list -E '...'. Um filtro silenciosamente estreito pode deixar testes importantes fora do job.

Estratégia de adoção em cinco etapas

Use este roteiro para uma migração reversível:

  1. Instale localmente e rode cargo nextest list.
  2. Compare com cargo test em todo o workspace.
  3. Corrija testes acoplados, recursos compartilhados e dependências de ordem.
  4. Adicione um job não bloqueante na CI durante alguns dias ou ciclos de pull request.
  5. Promova o job a obrigatório, mantendo doctests e qualquer verificação não coberta.

Depois da migração, registre os comandos no README ou no guia de contribuição:

cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo nextest run --workspace
cargo test --doc --workspace

Essa sequência dá à equipe um contrato claro. Para entender os diagnósticos no editor antes de chegar à CI, configure o rust-analyzer.

cargo-nextest ajuda na carreira?

Saber instalar uma ferramenta não é, sozinho, um diferencial forte. O valor profissional está em demonstrar que você entende confiabilidade de pipeline: testes isolados, relatórios úteis, investigação de flakiness, controle de recursos, cache e feedback rápido para pull requests.

Em um portfólio, você pode mostrar isso com:

  • uma suíte unitária e de integração bem separada;
  • .config/nextest.toml pequena e comentada;
  • relatório JUnit publicado pela CI;
  • doctests mantidos;
  • README com comandos reproduzíveis;
  • uma decisão documentada sobre retries e timeouts.

Esse tipo de maturidade é relevante para vagas Rust backend, infraestrutura, sistemas e bibliotecas. O guia de portfólio GitHub para Rust ajuda a apresentar essas escolhas sem transformar o repositório em uma coleção de badges.

Quem também trabalha com Go pode comparar a filosofia com o runner nativo da linguagem e as práticas reunidas no guia de testes em Go. A ferramenta muda, mas isolamento, determinismo e feedback rápido continuam sendo os objetivos.

Checklist de produção

Antes de tornar o nextest obrigatório, confirme:

  • cargo test --workspace e nextest produzem resultados compatíveis;
  • doctests possuem uma etapa própria;
  • o arquivo .config/nextest.toml está versionado;
  • o perfil de CI não aplica retries globais sem justificativa;
  • filtros foram validados com cargo nextest list;
  • testes lentos têm timeout coerente com sua categoria;
  • bancos, portas e arquivos são isolados;
  • a versão do runner é controlada;
  • o relatório JUnit é preservado mesmo quando há falha;
  • a equipe conhece o comando local equivalente ao pipeline.

Conclusão

O cargo-nextest vale a adoção quando a suíte Rust já pede mais controle do que o runner padrão oferece. Seu maior benefício não é um número universal de velocidade, mas uma execução mais estruturada: processos isolados, agendamento paralelo, filtros expressivos, perfis de CI, timeouts, retries seletivos e relatórios consumíveis.

Comece sem ruptura. Rode o nextest ao lado do cargo test, encontre testes dependentes de ordem, mantenha os doctests e promova o novo job somente depois que os resultados forem previsíveis. Assim, a ferramenta melhora o feedback da equipe sem esconder falhas nem criar uma pipeline que apenas uma pessoa sabe operar.

Para continuar, revise as boas práticas de testes em Rust, configure a pipeline de CI/CD e use o Criterion quando a pergunta for benchmark de performance — um problema diferente da execução funcional da suíte.

Perguntas frequentes

O que é cargo-nextest?

É um test runner para Rust que usa os testes compilados pelo Cargo e oferece execução isolada por processo, paralelismo, filtros, perfis, retries, timeouts e relatórios para CI.

cargo-nextest substitui cargo test?

Ele pode executar a maior parte da suíte, mas cargo test continua sendo a referência padrão. Mantenha cargo test --doc para doctests e valide a equivalência antes de trocar o comando obrigatório.

Como instalar cargo-nextest?

Execute cargo install cargo-nextest --locked e confirme com cargo nextest --version. Na CI, prefira um instalador controlado ou uma imagem que evite recompilar a ferramenta a cada job.

Como executar apenas um teste no nextest?

Use cargo nextest run -E 'test(nome)'. Para verificar o conjunto selecionado sem executá-lo, rode cargo nextest list -E 'test(nome)'.

Como configurar retries no cargo-nextest?

Defina retries no perfil ou em overrides de .config/nextest.toml. Restrinja-os a falhas transitórias conhecidas e remova a exceção quando a causa do teste flaky for corrigida.