Relatório de cobertura de testes unitários com Angular e JEST
Criando o projeto
O primeiro passo é criar o projeto e executá-lo para se certificar de que tudo está bem configurado:
ng new relatorio-cobertura
cd relatorio-cobertura/
ng serve
Se tudo correu bem você deverá ver algo como a imagem abaixo quando acessar o seguinte endereço http://localhost:4200
no seu navegador:
Removendo as dependências
Por padrão os projetos em Angular vêm com o Karma instalado. Como não vamos utilizá-lo, podemos removê-lo através do comando abaixo:
npm remove karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter
Os arquivos abaixo também podem ser removidos:
- /karma.conf.js
- /src/test.ts
Instalando e configurando JEST
Para instalar as dependências utilize o comando abaixo:
npm i -D jest @types/jest @angular-builders/jest
Abra o arquivo /tsconfig.spec.json
e efetue as seguintes alterações:
- Substitua o texto
jasmine
porjest
- Remova a referência ao
test.ts
O arquivo ficará da seguinte forma:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jest",
"node"
]
},
"files": [
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
No arquivo /tsconfig.json
adicione o valor jest
na propriedade "types"
conforme o exemplo abaixo:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"lib": [
"es2018",
"dom"
],
"types": [
"jest"
]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
},
}
Por fim abra o arquivo /angular.json
e troque a linha "builder": "@angular-devkit/build-angular:karma"
por "builder": "@angular-builders/jest:run"
Execute o comando ng test
e o resultado será:
Observação: quando criamos o projeto na primeira etapa, automaticamente o Angular cria um teste unitário src/app/app.component.spec.ts
.
Relatório de cobertura
Para habilitar o relatório de cobertura, abra o arquivo /angular.json
e adicione a propriedade "coverage": true
conforme a seguinte imagem:
Execute novamente o comando ng test
. Após executá-lo, será criada uma pasta chamada /coverage
na raíz do seu projeto. Abrindo o arquivo /coverage/lcov-report/index.html
é possível visualizar a cobertura dos testes:
Para testarmos a cobertura, vamos criar uma nova função, meuTeste()
, dentro do arquivo /app.component.ts
:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'relatorio-cobertura';
meuTeste() {
this.title = 'consolelog.com.br';
}
}
Ao executar novamente o teste, ng test
, veja que o relatório aponta uma porcentagem menor (85.71%):
Clicando no link app.component.ts
é possível visualizar quais trechos do código do componente que não foram cobertos pelos testes unitários:
Aumentando a cobertura
Para cobrir este trecho de código (método meuTeste()
) será necessário editar o arquivo /app.component.spec.ts
e adicionar um novo teste:
/* ... trecho acima ocultado ... */
it('deve trocar o title quando meuTeste() for chamado', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
fixture.componentInstance.meuTeste();
const app = fixture.componentInstance;
expect(app.title).toEqual('consolelog.com.br');
});
Veja que ao chamar o método meuTeste()
, espera-se que o valor to title
seja alterado para 'consolelog.com.br'
. É justamente esta validação que nosso teste unitário efetua.
Ao executar novamente o comando ng test
podemos ver que o novo trecho de código foi 100% coberto pelo novo teste unitário:
Considerações
A construção dos testes unitários é bem trabalhosa. Exige conhecimento, prática e tempo. Uma das grandes vantagens da construção dos testes unitários é que quem os constrói, precisa ter plena consciência da lógica empregada. Esta consciência permite uma eventual refatoração e/ou otimização de alguns trechos de código.