You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Testam, via código, a menor parte da aplicação, como módulos, fragmentos de código e funções de forma isolada.
Testes de integração
Testam, via código, a integração entre diferentes modulos e partes do sistema. Em aplicações web, podem estar a comunicação entre componentes em uma mesma página ou uma feature espalhada em diferentes seções.
Testes de aceitação
Usados principalmente em ambientes ageis, testam os critérios de aceite de uma estória/feature através de ferramentas como o Cucumber, envolvendo o time não técnico como stakholders primários (PO).
Testes de sistema
São testes de ponta a ponta, como o procedimento de buscar um produto, adicioná-lo ao carrinho e finalizar compra.
Spec
É a menor unidade do teste e é importante que ela não seja generica para não gerar muitos assets (expectativas).
Suit
É um grupo de specs
No BDD, os testes definem o comportamento do nosso código, e no TDD, os testes definem a estrutura exata do nosso código.
Ajeita o que precisa para o teste funcionar (Arrange - Setup)
Executa a ação que voce quer testar (Act - Exercise)
Verifica se aconteceu o que voce esperava (Assert - Verify)
Por isso, cada teste é dividido em 3 bloquinhos. É bom que cada bloquinho tenha uma linha separando-os.
Testes UI - Ponta a ponta
⚠️ Não usar mocks, stubs, fakes, etc, pois a intenção é testar um cenário mais realista possivel
Unit - Teste de unidade
Pega cada pedaço pequeno, como uma classe, um model, etc. Agora vamos usar mocks, stubs, fakes, etc para que cada teste não precise de outros para funcionar e não batermos em nada externo. Além disso, esses testes tem como função guiar o design do código.
Testes de Integração
Estão no meio dos dois tipos de teste citados acima. Nós batemos em ambientes externos uma vez, salvamos a resposta e usamos ela pra sempre.
É coerente ter muitos testes de unidade e pouco de integração pois são mais rápidos de escrever e executar.
Command
Não retorna nada
Muda alguma coisa
Se preocupa com mensagens passadas
Usa spies
Query
Retorna alguma coisa
Nao muda nada
Se preocupa com o retorno
Usa doubles
⚠️ Cuidado com testes frágeis. Tente rodar testes sozinhos pois eles não devem depender de outros para funcionar.
⚠️ Evite usar lógica nos testes. Exemplo: repetições, condições, etc.
⚠️ Cuidado ao descrever a descrição do teste. A descrição deve fazer sentido com o teste que foi escrito.
⚠️ Não escreva testes com multiplas verificações.
⚠️ Cuidado com setups grandes. Para resolver, use Design Patterns e conceitos de Orientação a Objetos
⚠️ Testes repetitivos
⚠️ Cuidado ao deixar os seus testes muito dry usando before/after, pois se torna dificil de ler e não sabemos de onde as coisas estão vindo. Podemos resolver isso deixando o código duplicado mesmo ou usando metodos.
É melhor não ter testes do ter testes ruins - Camila Campos
Quando escrevemos testes ruins, confiamos nele cegamente acreditando que a aplicação está funcionando quando isso pode não ser verdade. Mas quando não há testes, nada pode cogitar a garantia de que a aplicação funciona.
Se claro sobre o que o seu metodo está descrevendo.
Use contextos
Contextos são ótimos para fazer testes mais claros e organizados (os deixa mais fáceis de ler). Quando descrevemos
um contexto, comece com "quando", "com" ou "sem".
Deixe sua descrição pequena
Uma descrição pequena nunca deve ser maior que 40 caracters. Se isso acontecer voce deve separar usando um contexto.
Unica expectativa para o teste
A 'unica expectativa' tem mais a ver com 'cada teste deve fazer uma unica afirmação'. Isso vai ajudar voce a encontrar possíveis erros, indo diretamente no teste que está falhando e deixar seu código mais legivel. Isolando em
pedacinhos, voce quer que cada exemplo especifique um (apenas um) comportamento. Muitas expectativas no mesmo exemplo
é um sinal de que voce pode estar especificando muitos comportamentos esperados.
Teste todos os casos possíveis
Testar é uma boa prática, mas se voce não testar cada caso, não vai ser util. Teste validações, casos extremos e invalidações como "not found", "inexistente", "formatação errada", "presença", "tamanho inválido", etc
Usar mock ou não
Geralemnte a regra diz para não usar e testar casos reais quando possível. Mockar faz seus testes serem mais rápidos mas são dificeis de usar. Voce precisa entender e usá-los muito bem.
Crie apenas os dados que precisa
Se voce já trabalhou em um projeto médio (ou pequeno), deve saber que testes podem ser dificieis de rodar. Para resolver
esse problema, é importante não carregar mais dados do que o necessário. Além disso, se voce acha que precisa de deznas de records, voce provavelmente está enganado.
Use FactoryBot
Este é um tópico antigo, mas é bom lembrar. Não use fixtures porque eles não dificeis de controlar, use instancias do FactoryBot. Use eles para reduzir a verbosidade na criação de novos dados.
Teste o que voce ve
⚠️ Testar controllers?
Não use "deve" no começo da descrição dos testes
Guard
Podemos usar o guard para rodar apenas os testes que foram atualizados
Stubbing HTTP requests
As vezes voce precisa acesar serviços externos. Nesses casos, voce não pode realmente testar o serviço de verdade, mas voce deve usar stub com soluções como webmock.
É um framework do Facebook construído em javascript, desenvolvido inicialmente para testar aplicações em React (também do Facebook), mas hoje também está presente em outros projetos no frontend como Vue, Node, Angular, etc. Mas neste conteúdo, o abordaremos em relação ao Vue.
Instalando
Para instalar, basta rodar o script:
yarn add --dev jest
Para usar junto com o Vue, rode mais os seguintes comandos:
yarn global add @vue/cli
yarn add @vue/cli-plugin-unit-jest
Configurando
É possível configurar os seguintes parâmetros dentro do arquivo jest.config.js presente na raíz do projeto, junto com package.json:
Snapshots: são capturas de tela. No Rails, usamos o screenshot no meio do teste para ver a imagem da tela naquele ponto. No Jest é diferente: ele faz a captura a partir de um wrapper, retornando apenas o documento html mostrando alguns estilos css inline.
Coverage: é o que chamamos de cobertura de testes. No Rails usamos gems como o SimpleCov, passando por todos os controllers, models, etc. No Jest, ele irá passar por todos os componentes.
Para definir se essa cobertura será feita automaticamente ao rodar os testes usamos o parâmetro collectCoverage, que recebe um dado do tipo boolean que é false por padrão. Ao marcar essa opção como true, toda vez que rodarmos os testes a cobertura sempre será feita.
module.exports={collectCoverage: true}
Nem sempre é necessário testar todos os arquivos do projeto como a pasta de dependências do node_modules, arquivos css, imagens, etc. Então, podemos determinar quais arquivos e pastas serão cobertos ou não usando o parâmetro collectCoverageFrom. Exemplo:
module.exports={collectCoverageFrom: ["**/*.{js,vue}",// considera todos os arquivos do tipo js e vue"!**/node_modules/**",// ignora as dependencias"!**/test_helpers/**",// ignora essa pasta],}
Alias: a partir do parâmetro moduleNameMapper, podemos criar atalhos para importar uma pasta ou arquivo. Com ele, podemos usar como referencia a raiz do projeto e atrelar esse caminho a um nome ou simbolo. Então toda vez que formos importar algo em um arquivo, não importa onde o arquivo a ser importado esteja em relação a ele, pois podemos sempre usar o mesmo atalho. Exemplo:
// Importando sem aliasimportapifrom"../../../services/requests.js";
// Definindo um alias dentro do regexmodule.exports={moduleNameMapper: ["^@/(.*)$": "<rootDir>/js/services/$1"],}
// Importando com alias definido como: @importapifrom"@/requests.js";
Transform: o Jest só entende código em javascript. Então se houver algum código diferente (vindo do VueJS, TypeScript, etc) nos testes ele vai emitir algum erro. Então o transform faz justamente isso: transforma todo o código em javascript para que o Jest entenda. Para saber mais, recomendo um artigo sobre ele na doc do Jest.
module.exports={transform: {// process `*.vue` files with `vue-jest`".*\\.(vue)$": "vue-jest",},}
Babel: Assim como o transform, o Babel também tem a ver com conversão de código. Neste caso, a sua principal função é converter o código ECMAScript 2015 em uma versão compatível com versões antigas do JS presentes em navegadores e browsers mais antigos. Para saber mais, recomendo a documentação do Babel
Para rodar os testes, também precisamos adicionar o script no arquivo package.json:
"scripts": {"test": "jest"},
Assim, podemos rodar os testes tanto com yarn run test como yarn run jest (se estiver usando yarn)
Criando um componente no Vue
<template><form @submit.prevent="login"><spanv-if="submit">Login realizado com sucesso</span><labelfor="email">Email</label><inputid="email"type="email"v-model="form.email"/><strongv-if="!valid.email">CampoObrigatório</strong><labelfor="password">Senha</label><inputid="password"type="password"v-model="form.password"/><strongv-if="!valid.password">Campo Obrigatório</strong><buttontype="submit">Login</button>
</form></template><script>
export default {name: "AppForm",data: function(){return{form: {email: "",password: "",},valid: {email: true,password: true,},submit: false,};},methods: {login(){// Verifica o preenchimento dos camposthis.valid.email=this.form.email.length>0;this.valid.password=this.form.password.length>0;// O formulário é submetido se todos os campos forem validosthis.submit=this.valid.email&&this.valid.password;},},};
</script>
Montamos um componente para um formulário que valida o preenchimento dos campos de email e senha.
Ao submetê-lo, poderá ser apresentado uma mensagem de erro (caso não forem preenchidos) ou de sucesso (caso contrário).
Pode parecer simples, mas já podemos testar:
Renderização de elementos: verificando se o formulário está sendo mostrado corretamente;
Valores de entrada: preenchendo os campos;
Chamada de ações: ao submeter o formulário;
Resultados: ao verificar quais mensagens foram mostradas.
Vale lembrar, que ações são eventos assíncronos como o clicar de um botão, preenchimento dos campos ou retorno de uma API, portanto, é recomendado o uso de async await nesses casos. Para usá-los, precisamos do regenerator-runtime
Criando arquivos de teste
Para que o Jest entenda que um dado arquivo se trata de um teste, ele precisa:
Estar dentro de uma pasta chamada __tests__.
Estar com o prefixo final .test.js ou .spec.js. Exemplo: meu_teste_maroto.test.js
Ter pelo menos um teste, se não um alerta será emitido.
Testando
importAppFormfrom"js/components/AppForm";import{mount}from"@vue/test-utils";// Usaremos para os testes assincronosimport"regenerator-runtime/runtime";// Construção do wrapperconstform=mount(AppForm);describe("user",()=>{it("access form without errors",()=>{// Mensagem de sucesso não deve aparecerexpect(form.find("span").exists()).toBe(false);// Mensagens de erro não devem aparecerconsterrors=form.findAll("strong");expect(errors.length).toBe(0);// Formulárioexpect(form.find("label").text()).toBe("Email");expect(form.findAll("label").at(1).text()).toBe("Senha");expect(form.find("input").element.value).toBe("");expect(form.findAll("input").at(1).element.value).toBe("");expect(form.find("button").text()).toBe("Login");});it("must filled fields",async()=>{awaitform.find("form").trigger('submit.prevent');// Mensagens de erro devem aparecerconsterrors=form.findAll("strong");expect(errors.length).toBe(2);expect(errors.at(0).text()).toBe("Campo Obrigatório");expect(errors.at(1).text()).toBe("Campo Obrigatório");// Mensagem de sucesso não deve aparecerexpect(form.find("span").exists()).toBe(false);});it("submit form successfully",async()=>{// Preenche os campos e submete o form novamenteawaitform.find("input").setValue("[email protected]");awaitform.findAll("input").at(1).setValue("senha123");awaitform.find("form").trigger('submit.prevent');// Mensagens de erro desaparecemconsterrors=form.findAll("strong");expect(errors.length).toBe(0);// Mensagem de sucesso apareceexpect(form.find("span").exists()).toBe(true);expect(form.find("span").text()).toBe("Login realizado com sucesso");})});
A partir desses testes, podemos analisar alguns pontos:
Setup: no caso apresentado, não foi necessário fazer muitas configurações antes de iniciar os testes, apenas a construção do componente em si. Na verdade, isso vai depender muito do grau de complexidade do próprio componente, isto é, se ele depende de props, API's, funções externas, vuex ou outras dependências que podem ser estranhos para o Jest, sendo necessário mocá-los.
Wrapper: de acordo com a documentação, "wrapper" é o objeto que contém o componente que foi montado. No nosso exemplo, o montamos com o mount. Também podemos chamá-lo simplesmente de "component" ou do que ele representa como "form", deixando o teste mais legível. Pode ser apenas uma questão de nomenclatura, mas é importante citar pois nas documentações ele sempre será chamado de wrapper.
Variáveis: construímos o wrapper e o definimos como uma variável global, portanto, foi utilizado em todos os testes. Já as mensagens de erro foram declaradas localmente, logo, só podem ser acessadas dentro de cada teste onde foram declaradas.
find: é possível encontrar um wrapper a partir outro usando como referencia um seletor (seja ele uma tag html, classe ou id), retornando sempre o primeiro resultado.
findAll: é possível encontrar vários wrappers a partir de um, retornando um array com todos os resultados. Por isso, o Jest o chama de WrapperArray. Para acessar cada resultado, podemos usar o at() em seguida, levando a posição que pode ir de 0 ao tamanho do array menos um.
trigger: chama uma determinada ação, que pode um 'click' ou 'submit.prevent' para o caso do formulário.
setValue: atribui um valor a um elemento de entrada, no nosso caso, o input.
exists: retorna um boolean, indicando se aquele wrapper existe ou não.
toBe: apresenta o resultado do teste, como o próprio nome diz, "deve ser", ou seja, "deve ser verdadeiro", "deve ser falso", "deve ser 0", etc.
Metodos do Wrapper
Propriedade
Descrição
attributes
Retorna os atributos do DOM
classes
Retorna um array de classes
contains
Verifica se aquele wrapper da macth com algum seletor ou outro componente
destroy
Destroi o wrapper
emitted
Retorna um objeto com os eventos emitidos por aquele wrapper
exists
Retorna un boolen, indicando se aquele elemento existe
find
Retorna um selector ao buscar por um elemento no wrapper que pode ou não existir
findComponent
Ideal para buscar componentes dentro de componentes
findAll
Retorna um array com todos os seletores encontrados na busca
findAllComponentes
Retorna um array com todos os componentes encontrados
html
get
Funciona quase como o find, mas vai emitir um erro o elemento buscado não for encontrado
setProps
ode manipular diretamente as props do componente
setData
pode manipular diretamente os dados de date do componente
Testando a tela em diferentes larguras
Por padrão, o tamanho de tela que o Jest usa como referencia é 1024px de largura e 768px de altura, mas podemos alterar esses valores para testar em outros tamanhos de tela. Vou usar um exemplo simples com uma mudança de texto da versão mobile para desktop.
<template>
<divclass="message__container">
<h1class="message__desk">Bem vindo a versão desktop</h1>
<h1class="message__mobile">Bem vindo a versão mobile</h1>
</div>
</template>
<script>
exportdefault { name:"AppMessage"}
</script>
<style>
.message__mobile {display: block;}.message__desk {display: none;}@media (min-width: 1200px) {.message__mobile {display: none; }.message__desk {display: block; }}
</style>
importAppMessagefrom"./AppMessage";describe("must render",()=>{it("desktop message",()=>{constcomponent=mount(AppMessage);expect(component.find("h1").text()).toBe("Bem vindo a versão mobile");global.innerWidth=toPx;global.dispatchEvent(newEvent('resize'));})})