Olá Habr! Este guia é a primeira parte de uma série planejada de artigos sobre uma estrutura de teste tão boa como o Jest. O material será útil para iniciantes e para aqueles que estão começando a se familiarizar com os testes e gostaria de estudar essa estrutura. Na primeira parte, discutiremos: como iniciar o gracejo, como escrever um teste simples e quais métodos existem para comparar os valores a serem verificados com os esperados. Quem se importa - bem-vindo ao kat!O que é Jest?
Conforme indicado na página inicial do projeto:O Jest é um incrível ambiente de teste de JavaScript com foco na simplicidade.
E, de fato, Jest é muito simples. Não requer configurações adicionais, fácil de entender e usar, e também possui uma documentação muito boa. Ótimo para projetos que usam Nó, Reagir, Angular, Vue, Babel, TypeScript e muito mais.Também é de código aberto e suportado pelo Facebook.Instalação
Para instalar o Jest em seu projeto, faça:npm install --save-dev jest
Se você estiver usando fio:yarn add --dev jest
Após a instalação, você pode atualizar a seção de scripts do seu package.json:“scripts” : {
“test”: “jest”
}
Com esta simples chamada, já podemos executar nossos testes (na verdade, o gracejo exigirá pelo menos um teste para existir).Você também pode instalar globalmente (mas eu não recomendaria isso, pois para mim a instalação global de módulos é uma prática recomendada):npm install jest --global
E de acordo com o fio:yarn global add jest
Depois disso, você pode usar o gracejo diretamente da linha de comando.Ao chamar o comando jest --init na raiz do projeto, depois de responder a algumas perguntas, você obterá o arquivo de configurações jest.config.js. Ou você pode adicionar a configuração diretamente ao seu package.json. Para fazer isso, adicione a chave "jest" à raiz json e, no objeto correspondente, você pode adicionar as configurações necessárias. Analisaremos as opções em si mais tarde. Isso não é necessário neste estágio, pois o gracejo pode ser usado imediatamente, sem configurações adicionais.Primeiro teste
Vamos criar o arquivo first.test.js e escrever nosso primeiro teste:
test('My first test', () => {
expect(Math.max(1, 5, 10)).toBe(10);
});
E execute nossos testes usando o npm run test ou diretamente com o comando jest (se instalado globalmente). Após o lançamento, veremos um relatório sobre a aprovação nos testes. <b>PASS</b> ./first.test.js
✓ My first test (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.618 s, estimated 1 s
Vamos terminar nosso teste e executar o gracejo novamente:
test('My first test', () => {
expect(Math.max(1, 5, 10)).toBe(5);
});
Como podemos ver, agora nosso teste não passa no teste. O Jest exibe informações detalhadas sobre onde o problema ocorreu, qual foi o resultado esperado e o que obtivemos.Agora vamos analisar o código do teste em si. Função de testeusado para criar um novo teste. São necessários três argumentos (no exemplo, usamos uma chamada com dois argumentos). A primeira é uma linha com o nome do teste, sua brincadeira será exibida no relatório. A segunda é uma função que contém a lógica do nosso teste. Você também pode usar o terceiro argumento - tempo limite. É opcional e seu valor padrão é de 5 segundos. É definido em milissegundos. Este parâmetro é necessário quando trabalhamos com código assíncrono e retornamos uma promessa da função de teste. Indica quanto tempo a brincadeira deve esperar a promessa se resolver. Após esse período, se a promessa não for permitida - o gracejo considerará que o teste falhou. Mais informações sobre como trabalhar com chamadas assíncronas estão nas seguintes partes. Como alternativa, você pode usá- lo () em vez de test ().. Não há diferença entre essas chamadas. it () é apenas um alias na função test () .Dentro da função de teste, chamamos primeiro de expect () . Para ele, passamos o valor que queremos verificar. No nosso caso, este é o resultado da chamada Math.max (1, 5, 10) . expect () retorna um objeto de wrapper que possui vários métodos para comparar o valor resultante com o esperado. Um desses métodos que usamos é toBe .Vejamos o principal desses métodos:- toBe() — , , . Object.is(). === 0 -0, NaN c NaN.
- toEqual() — , . . . .
test('toEqual with objects', () => {
expect({ foo: 'foo', subObject: { baz: 'baz' } })
.toEqual({ foo: 'foo', subObject: { baz: 'baz' } });
expect({ foo: 'foo', subObject: { num: 0 } })
.toEqual({ foo: 'foo', subObject: { baz: 'baz' } });
});
test('toEqual with arrays', () => {
expect([11, 19, 5]).toEqual([11, 19, 5]);
expect([11, 19, 5]).toEqual([11, 19]);
});
- toContain() — . ===.
const arr = ['apple', 'orange', 'banana'];
expect(arr).toContain('banana');
expect(new Set(arr)).toContain('banana');
expect('apple, orange, banana').toContain('banana');
- toContainEqual() — .
expect([{a: 1}, {b: 2}]).toContainEqual({a: 1});
- toHaveLength() — length .
expect([1, 2, 3, 4]).toHaveLength(4);
expect('foo').toHaveLength(3);
expect({ length: 1 }).toHaveLength(1);
- toBeNull() — null.
- toBeUndefined() — undefined.
- toBeDefined() — toBeUndefined. !== undefined.
- toBeTruthy() — true. false, null, undefined, 0, NaN .
- toBeFalsy() — toBeTruthy(). false.
- toBeGreaterThan() toBeGreaterThanOrEqual() — , >, >=.
- toBeLessThan() toBeLessThanOrEqual() — toBeGreaterThan() toBeGreaterThanOrEqual()
- toBeCloseTo() — , , . .
const num = 0.1 + 0.2;
expect(num).toBeCloseTo(0.3);
expect(Math.PI).toBeCloseTo(3.14, 2);
- toMatch() — .
expect('Banana').toMatch(/Ba/);
- toThrow () - usado quando é necessário verificar a exceção. Você pode verificar o fato do erro em si e verificar se há exceções de lançamento de uma determinada classe, pela mensagem de erro ou pela correspondência da mensagem com a expressão regular.
function funcWithError() {
throw new Error('some error');
}
expect(funcWithError).toThrow();
expect(funcWithError).toThrow(Error);
expect(funcWithError).toThrow('some error');
expect(funcWithError).toThrow(/some/);
- not - essa propriedade permite verificar a desigualdade. Ele fornece um objeto que possui todos os métodos listados acima, mas eles funcionarão ao contrário.
expect(true).not.toBe(false);
expect({ foo: 'bar' }).not.toEqual({});
function funcWithoutError() {}
expect(funcWithoutError).not.toThrow();
Vamos escrever alguns testes simples. Primeiro, crie um módulo simples que contenha vários métodos para trabalhar com círculos.
const area = (radius) => Math.PI * radius ** 2;
const circumference = (radius) => 2 * Math.PI * radius;
module.exports = { area, circumference };
Em seguida, adicione os testes:
const circle = require('../src/circle');
test('Circle area', () => {
expect(circle.area(5)).toBeCloseTo(78.54);
expect(circle.area()).toBeNaN();
});
test('Circumference', () => {
expect(circle.circumference(11)).toBeCloseTo(69.1, 1);
expect(circle.circumference()).toBeNaN();
});
Nestes testes, verificamos o resultado de 2 métodos - área e circunferência . Usando o método toBeCloseTo, verificamos o resultado esperado. No primeiro caso, verificamos ou a área calculada do círculo com um raio de 5 é aproximadamente igual a 78,54, enquanto a diferença com o valor obtido (será 78,53981633974483) não é grande e o teste será contado. No segundo, indicamos que estamos interessados em verificar com uma casa decimal. Também chamamos nossos métodos sem argumentos e verificamos o resultado usando toBeNaN . Como o resultado de sua execução será NaN, os testes serão aprovados com sucesso.Vamos dar outro exemplo. Vamos criar uma função que irá filtrar uma variedade de produtos por preço:
const byPriceRange = (products, min, max) =>
products.filter(item => item.price >= min && item.price <= max);
module.exports = { byPriceRange };
E adicione um teste:
const productFilter = require('../src/producFilter');
const products = [
{ name: 'onion', price: 12 },
{ name: 'tomato', price: 26 },
{ name: 'banana', price: 29 },
{ name: 'orange', price: 38 }
];
test('Test product filter by range', () => {
const FROM = 15;
const TO = 30;
const filteredProducts = productFilter.byPriceRange(products, FROM, TO);
expect(filteredProducts).toHaveLength(2);
expect(filteredProducts).toContainEqual({ name: 'tomato', price: 26 });
expect(filteredProducts).toEqual([{ name: 'tomato', price: 26 }, { name: 'banana', price: 29 }]);
expect(filteredProducts[0].price).toBeGreaterThanOrEqual(FROM);
expect(filteredProducts[1].price).toBeLessThanOrEqual(TO);
expect(filteredProducts).not.toContainEqual({ name: 'orange', price: 38 });
});
Neste teste, verificaremos o resultado da função byRangePrice . Primeiro, verificamos a correspondência do comprimento da matriz resultante com a esperada - 2. A próxima verificação exige que o elemento contenha o elemento - {name: 'tomato', price: 26}. O objeto na matriz e o objeto passado paraContainEqual são dois objetos diferentes, não uma referência ao mesmo. Mas toContainEqual comparará cada propriedade. Como os dois objetos são idênticos, a verificação será bem-sucedida. Em seguida, usamos toEqual para verificar a estrutura de toda a matriz e seus elementos. Os toBeGreaterThanOrEqual e métodos toBeLessThanOrEqual vai nos ajudar a verificar o preço do primeiro e do segundo elemento da matriz. E, finalmente, chamando not.toContainEqualirá verificar se o elemento está contido na matriz - {name: 'orange', price: 38}, que, por condição, não deve estar lá.Nestes exemplos, escrevemos alguns testes simples usando as funções de verificação descritas acima. Nas partes a seguir, discutiremos o trabalho com código assíncrono, as funções de gracejo que não foram abordadas nesta parte do tutorial, falaremos sobre sua configuração e muito mais.