Onde os testes são executados

Normalmente, os testes automatizados podem ser executados executando um script manualmente ou usando um auxiliar de um framework de testes, geralmente chamado de executor de testes, para encontrar e executar testes. No entanto, nem sempre você precisa executar os scripts manualmente. Existem várias maneiras de executar seus testes que podem fornecer feedback e confiança em diferentes pontos durante o ciclo de vida de desenvolvimento.

Script de pré-requisito

Os projetos da Web geralmente têm um arquivo de configuração (o arquivo package.json) definido pelo npm, pnpm, Bun ou semelhante. Esse arquivo de configuração contém as dependências do projeto e outras informações, bem como scripts auxiliares. Esses scripts auxiliares podem incluir como criar, executar ou testar seu projeto.

Dentro de package.json, será necessário adicionar um script chamado test que descreve como executar seus testes. Isso é importante porque, ao usar o npm ou uma ferramenta semelhante, o script"test" tem um significado especial. Esse script pode simplesmente apontar para um único arquivo que gera uma exceção, como node tests.js, mas recomendamos usá-lo para apontar para um executor de testes estabelecido.

Se você estiver usando o Vitest como executor de testes, o arquivo package.json ficará assim:

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

Se você executar npm test com esse arquivo, o conjunto padrão de testes do Vitest será executado uma vez. No Vitest, o padrão é encontrar e executar todos os arquivos que terminam com ".test.js" ou semelhante. Dependendo do executor de testes escolhido, o comando pode ser um pouco diferente.

Optamos por usar o Vitest, um framework de teste cada vez mais conhecido, como exemplos ao longo deste curso. Leia mais sobre essa decisão em Vitest como um executor de testes. No entanto, é importante lembrar que frameworks e executores de teste, mesmo em vários idiomas, tendem a ter uma linguagem comum.

Invocação de teste manual

O acionamento manual dos testes automatizados (como o uso de npm test no exemplo anterior) pode ser prático enquanto você está trabalhando ativamente em uma base de código. Escrever testes para um recurso durante o desenvolvimento dele pode ajudar você a ter uma noção de como o recurso deve funcionar. Isso toca no conceito de desenvolvimento orientado a testes (TDD, na sigla em inglês).

Os executores de teste normalmente têm um comando curto que pode ser invocado para executar alguns ou todos os testes e, possivelmente, um modo inspetor que executa novamente os testes enquanto você os salva. Todas essas opções são úteis ao desenvolver um novo recurso e foram projetadas para facilitar a criação de um novo recurso, de testes ou de ambos, com feedback rápido. O Vitest, por exemplo, opera no modo inspetor por padrão: o comando vitest monitora as mudanças e executa novamente todos os testes encontrados. Recomendamos deixar essa opção aberta em outra janela enquanto cria testes, para que você possa receber feedback rápido sobre os testes à medida que os desenvolve.

Alguns executores também permitem marcar testes como only no código. Se o código incluir testes only, somente eles serão acionados quando você os executar, tornando o desenvolvimento de testes mais rápido e fácil de resolver. Mesmo que todos os testes sejam concluídos rapidamente, o uso de only pode reduzir a sobrecarga e remover a distração da execução de testes não relacionados ao recurso ou teste em que você está trabalhando.

Para projetos pequenos, especialmente projetos com apenas um desenvolvedor, você também pode desenvolver o hábito de executar todo o pacote de testes da base de código regularmente. Isso é especialmente útil se seus testes forem pequenos e forem concluídos rapidamente (em não mais do que alguns segundos para todos os testes), para que você possa garantir que tudo esteja funcionando antes de seguir em frente.

Executar testes como parte do pré-envio ou da revisão

Muitos projetos optam por confirmar se uma base de código está funcionando corretamente quando o código é mesclado de volta à ramificação main. Se você não tem experiência com testes, mas contribuiu com projetos de código aberto no passado, provavelmente notou que parte do processo de solicitação de envio (PR, na sigla em inglês) confirma que todos os testes do projeto foram aprovados, o que significa que sua nova e empolgante contribuição não afetou negativamente o projeto existente.

Se você executar os testes localmente, o repositório on-line do projeto (por exemplo, o GitHub ou outro serviço de hospedagem de código) não saberá se os testes estão sendo aprovados. Por isso, executar testes como uma tarefa de pré-envio deixa claro para todos os colaboradores que tudo está funcionando.

O GitHub, por exemplo, refere-se a isso como "verificações de status", que podem ser adicionadas nas ações do GitHub. As ações do GitHub são fundamentalmente um tipo de teste: cada etapa precisa ser bem-sucedida (não falhar ou gerar uma Error) para que a ação seja aprovada. É possível aplicar ações a todos os PRs de um projeto, e um projeto pode exigir que as ações sejam transmitidas antes de contribuir com o código. A ação padrão do Node.js do GitHub executa npm test como uma das etapas.

Captura de tela de um processo de teste do GitHub Actions.
Uma captura de tela de um processo de teste do GitHub Actions.

Essa abordagem de teste tenta garantir que sua base de código esteja sempre "verde", não aceitando código que não execute os testes corretamente.

Executar testes como parte da integração contínua

Depois que o PR verde for aceito, a maioria das bases de código vai executar testes novamente com base na ramificação main do projeto, em vez do PR anterior. Isso pode acontecer imediatamente ou regularmente (por exemplo, de hora em hora ou todas as noites). Esses resultados geralmente são mostrados como parte de um painel de integração contínua (CI) que mostra a integridade geral do projeto.

Essa etapa de CI pode parecer redundante, especialmente em projetos com pequenas bases de código. Os testes são aprovados durante a revisão e, portanto, são aprovados quando uma alteração é feita. No entanto, isso nem sempre é verdade. Seus testes podem falhar repentinamente, mesmo depois de produzir resultados verdes com sucesso. Confira alguns motivos para isso:

  • Várias mudanças foram aceitas "de uma vez", também conhecida como condição de corrida, e afetam umas às outras de maneiras sutis e não testadas.
  • Seus testes não são reproduzíveis ou testam código "instável" e podem ser aprovados ou reprovados sem alterações no código.
    • Isso pode ocorrer se você depende de sistemas externos à sua base de código. Para um proxy, imagine testar se Math.random() > 0.05: isso falharia aleatoriamente em 5% das vezes.
  • Alguns testes são muito caros ou caros para serem executados em todos os PRs, como testes completos (mais sobre isso em tipos de testes automatizados), e eles podem falhar ao longo do tempo sem sempre alertar.

Nenhum desses problemas é impossível de superar, mas vale a pena perceber que os testes e o desenvolvimento de software em geral nunca serão uma ciência exata.

Uma interrupção na reversão

Quando os testes são executados como parte da integração contínua, e mesmo quando eles são executados como parte de uma verificação de status, é possível que o build fique em um estado "vermelho" ou em outro estado que indique que os testes estão falhando. Como mencionado anteriormente, isso pode acontecer por vários motivos, incluindo disputas no envio de testes ou testes instáveis.

Para projetos menores, seu instinto pode ser tratá-los como uma crise! Interrompa tudo, reverta ou reverta a alteração ofensiva e volte a um estado bom conhecido. Essa pode ser uma abordagem válida, mas é importante lembrar que os testes (e o software em geral) são um meio para um fim, não um objetivo em si. Seu objetivo provavelmente é criar um software, e não passar em todos os testes. Em vez disso, você pode avançar acompanhando a alteração interruptiva com outra que corrige os testes com falha.

Por outro lado, talvez você já tenha visto ou trabalhado em grandes projetos que existem em um estado perpetuamente corrompido. Ou pior, o projeto grande tem um teste instável que falha com frequência suficiente para causar fadiga do alarme nos desenvolvedores. Esse geralmente é um problema existencial que os líderes precisam resolver: esses testes podem até ser desativados porque são vistos como "prestes a atrapalhar o desenvolvimento".

Não há uma correção rápida para isso, mas pode ajudar a ter mais confiança ao programar testes (aprimorar a qualificação) e reduzir o escopo (simplificação) dos testes para que as falhas sejam identificadas com mais facilidade. Um número maior de testes de componente ou testes de integração (mais sobre tipos em Tipos de testes automatizados) pode fornecer mais confiança do que um enorme teste completo que é difícil de manter e tenta fazer tudo de uma vez.

Recursos

Teste seu conhecimento

Qual é o nome do script especial que o npm e programas semelhantes procuram para os testes?

verificar
teste
pré-enviar
verificar