paint-brush
Jasmine: um guia para iniciantes sobre funções puras e testes básicospor@marcinwosinek
200 leituras

Jasmine: um guia para iniciantes sobre funções puras e testes básicos

por Marcin Wosinek6m2024/02/11
Read on Terminal Reader

Muito longo; Para ler

Funções puras são o caso perfeito para testes unitários. Para uma determinada entrada, esperamos sempre a mesma saída – não há nenhum estado interno envolvido. Vejamos alguns exemplos e alguns testes simples que verificam se os métodos funcionam conforme o esperado.
featured image - Jasmine: um guia para iniciantes sobre funções puras e testes básicos
Marcin Wosinek HackerNoon profile picture

Funções puras são o caso perfeito para testes unitários. Para uma determinada entrada, esperamos sempre a mesma saída – não há nenhum estado interno envolvido. Vejamos alguns exemplos e alguns testes simples que verificam se os métodos funcionam conforme o esperado.

Jasmim

Jasmine é uma estrutura de teste de unidade para JavaScript. Ele pode executar testes em Node.js ou no navegador. É usado na estrutura Angular e é especialmente popular em projetos baseados em Angular. É uma escolha sólida para projetos Vanilla JS ou também para projetos baseados em outras estruturas.

Teste de caminho feliz

O teste do caminho feliz é quando testamos um método com entradas que devem funcionar normalmente. Os argumentos são válidos e dentro de limites razoáveis. Esses testes verificam se o método faz seu trabalho corretamente – os casos de teste devem ser exemplos diretos de como o método é explicado em sua documentação.


Exemplos de pseudocódigo:

  • expect(add(2, 2)).toBe(4) ,


  • expect(concatenate(“Lorem”, “Ipsum”)).toBe(“LoremIpsum”)


Esses testes têm como objetivo capturá-lo automaticamente sempre que o comportamento da chave do método for interrompido.

Métodos

Vejamos alguns métodos simples: operações simples que podemos precisar em algumas aplicações do mundo real.


Todas as implementações são bastante simplificadas – todos os métodos falharão de maneira feia se fornecermos a eles parâmetros que diferem ligeiramente do esperado. O código está longe de ser robusto.

saudar

Método que cumprimenta o usuário com nome e sobrenome:

 export function greet(name, surname) { return `Hello ${name} ${surname}!`; }

encontro curto

shortDate é um método de formatação que pega um objeto de data e o retorna formatado como uma string curta. O código:

 export function shortDate(date) { return date.toISOString().substring(0, 10); }

elipse

ellipsis pega uma string de texto longa e um parâmetro de comprimento opcional e, em seguida, corta a string para caber dentro do limite:

 export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; }

traduzir

Um método que fornece valores de string traduzidos para um par key e lang . É uma implementação simplificada do que poderia ser substituído por bibliotecas de tradução mais avançadas.

 export function translate(key, lang = "en") { switch (lang) { case "en": switch (key) { case "hello": return "Hello!"; } case "pl": switch (key) { case "hello": return "Cześć!"; } } }

aplicarDesconto

Método para aplicar um desconto percentual a um preço. Pode parecer um exagero com essa implementação ingênua, mas mais tarde, quando começarmos a investigar casos extremos, tudo ficará muito mais interessante.

 export function applyDiscount(price, discountPercentage) { return price - (price * discountPercentage) / 100; }

calcularPreço

Este calcula o preço total ao comprar várias unidades a um determinado preço. Também ficará mais complicado depois de adicionar casos extremos interessantes.

 export function calculatePrice(unitPrice, quantity) { return unitPrice * quantity; }

Código JS completo

O código JS completo, src/main.js :

 export function greet(name, surname) { return `Hello ${name} ${surname}!`; } export function shortDate(date) { return date.toISOString().substring(0, 10); } export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; } export function translate(key, lang = "en") { switch (lang) { case "en": switch (key) { case "hello": return "Hello!"; } case "pl": switch (key) { case "hello": return "Cześć!"; } } } export function applyDiscount(price, discountPercentage) { return price - (price * discountPercentage) / 100; } export function calculatePrice(unitPrice, quantity) { return unitPrice * quantity; }

Adicionando testes Jasmine

Para adicionar Jasmine, vamos começar convertendo a pasta em um pacote npm:

 $ npm init -y Wrote to …/package.json: …


Então podemos instalar o pacote Jasmine:

 $ npm install --save-dev jasmine added 42 packages, and audited 43 packages in 2s 13 packages are looking for funding run `npm fund` for details found 0 vulnerabilities


Então podemos gerar pastas e arquivos usados pelo Jasmine:

 $ npx jasmine init (no output)


Este comando gera o seguinte:

  • spec/ —uma pasta onde podemos colocar os arquivos *.spec.js com o teste, e


  • spec/support/jasmine.json —um arquivo com a configuração do Jasmine.

Testes unitários

Para os testes de unidade a seguir, estou focando apenas no caminho feliz – verifico se o resultado é o esperado para entradas razoáveis. O teste deve ser autoexplicativo, então vamos dar uma olhada neles:

 import { greet, shortDate, ellipsis, translate, applyDiscount, calculatePrice, } from "../src/main.js"; describe("main", () => { describe("greet", () => { it("should greet by name and surname", () => { expect(greet("Lorem", "Ipsum")).toEqual("Hello Lorem Ipsum!"); }); }); describe("shortDate", () => { it("should format correclty date", () => { const date = new Date("2023-11-02"); expect(shortDate(date)).toEqual("2023-11-02"); }); }); describe("shortDate", () => { it("should shorten long text at 50 chars", () => { expect( ellipsis( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a faucibus massa." ) ).toEqual("Lorem ipsum dolor sit amet, consectetur adipiscing…"); }); it("should leave short text unchanged", () => { expect(ellipsis("Lorem ipsum sin dolor")).toEqual( "Lorem ipsum sin dolor" ); }); it("should shorten to custom length", () => { expect(ellipsis("Lorem ipsum sin dolor", 10)).toEqual("Lorem ipsu…"); }); }); describe("translate", () => { it("should translate to supported langauges", () => { expect(translate("hello", "en")).toEqual("Hello!"); expect(translate("hello", "pl")).toEqual("Cześć!"); }); }); describe("applyDiscount", () => { it("should lower the price accordingly", () => { expect(applyDiscount(120, 25)).toEqual(90); expect(applyDiscount(8, 50)).toEqual(4); }); }); describe("calculatePrice", () => { it("should find a price of many products", () => { expect(calculatePrice(4, 3)).toEqual(12); expect(calculatePrice(9, 0.5)).toEqual(4.5); }); }); });

(arquivo spec/main.spec.js )

Executando testes

Para executar os testes, podemos adicionar o seguinte script ao package.json :

 .. "scripts": { "test": "jasmine" }, …


Com isso implementado, npm run test executa nossos testes:

 $ npm run test > [email protected] test > jasmine Randomized with seed 76873 Started ........ 8 specs, 0 failures Finished in 0.004 seconds Randomized with seed 76873 (jasmine --random=true --seed=76873)

Resumo

Neste post, demos uma olhada em um exemplo simples de código JS e como ele pode ser coberto por testes unitários. Você pode encontrar o exemplo de código completo no GitHub .


Também publicado aqui