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.
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.
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.
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.
Método que cumprimenta o usuário com nome e sobrenome:
export function greet(name, surname) { return `Hello ${name} ${surname}!`; }
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); }
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; }
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ść!"; } } }
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; }
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; }
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; }
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.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
)
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)
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