Чистые функции — идеальный случай для модульного тестирования. Для данного входного сигнала мы всегда ожидаем одного и того же результата — никакого внутреннего состояния при этом не требуется. Давайте рассмотрим несколько примеров и несколько простых тестов, которые проверяют, работают ли методы должным образом.
Jasmine — это среда модульного тестирования для JavaScript. Он может запускать тесты как в Node.js, так и в браузере. Он используется в среде Angular и особенно популярен в проектах на его основе. Это хороший выбор для проектов Vanilla JS, а также проектов, основанных на других платформах.
Тестирование счастливого пути — это когда мы тестируем метод с входными данными, которые, как ожидается, будут работать нормально. Аргументы действительны и находятся в разумных пределах. Эти тесты проверяют, правильно ли метод выполняет свою работу — тестовые примеры должны быть простыми примерами того, как метод объясняется в его документации.
Примеры псевдокодов:
expect(add(2, 2)).toBe(4)
,
expect(concatenate(“Lorem”, “Ipsum”)).toBe(“LoremIpsum”)
Эти тесты предназначены для автоматического обнаружения этого каждый раз, когда поведение ключа метода нарушается.
Давайте рассмотрим несколько простых методов: простые операции, которые могут нам понадобиться в некоторых реальных приложениях.
Все реализации сильно упрощены — все методы будут некрасиво ломаться, если только мы предоставим им параметры, немного отличающиеся от ожидаемых. Код далек от надежности.
Метод, который приветствует пользователя именем и фамилией:
export function greet(name, surname) { return `Hello ${name} ${surname}!`; }
shortDate
— это метод форматирования, который принимает объект даты и возвращает его в виде короткой строки. Код:
export function shortDate(date) { return date.toISOString().substring(0, 10); }
ellipsis
принимает длинную текстовую строку и необязательный параметр длины, а затем обрезает строку, чтобы она соответствовала пределу:
export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; }
Метод, который предоставляет переведенные строковые значения для пары key
и lang
. Это упрощенная реализация того, что можно заменить более продвинутыми библиотеками перевода.
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; }
Полный код JS, 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; }
Чтобы добавить Jasmine, начнем с преобразования папки в пакет npm:
$ npm init -y Wrote to …/package.json: …
Затем мы можем установить пакет 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
Затем мы можем генерировать папки и файлы, используемые Jasmine:
$ npx jasmine init (no output)
Эта команда генерирует следующее:
spec/
— папка, в которую мы можем поместить файлы *.spec.js
с тестом, и
spec/support/jasmine.json
— файл с конфигом Jasmine.В следующих модульных тестах я концентрируюсь только на счастливом пути — я проверяю, соответствует ли результат ожидаемому для разумных входных данных. Тест не требует пояснений, поэтому давайте взглянем на них:
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); }); }); });
( spec/main.spec.js
)
Чтобы запустить тесты, мы можем добавить в package.json
следующий скрипт:
.. "scripts": { "test": "jasmine" }, …
После этого npm run test
запускает наши тесты:
$ 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)
В этом посте мы рассмотрели простой пример JS-кода и то, как его можно охватить с помощью модульных тестов. Полный пример кода вы можете найти на GitHub .
Также опубликовано здесь