Какая функция должна оборачивать тесты в тест фреймворке jasmine

Обновлено: 02.07.2024

Документ рассказывает, каким образом писать юнит-тесты, каким образом это делать с использованием Jasmine, как стоит делать и как поступать не следует.

Примеры тестов (далее - спеков) находятся в проекте nano.nano_api по адресу /spec/javascripts и доступны в браузере по адресу /specs

Как должны выглядеть тесты.

Юнит-тест должен представлять из себя несколько примеров, демонстрирующих, каким образом программа преобразует вход в выход посредством отдельных частей своего функционала (блоков или юнитов). Юнит-тест придумывается самим разработчиком и должен:

  • Быть максимально атомарным
  • Сравнивать результат вычислений (действий) тестируемого блока с неким результатом, полученным другим способом
  • Иметь описание согласно проверямому действию
  • Служить примером использования отдельных функциональных блоков
  • Учитывать крайние случаи (значения вроде undefined, отсутствие данных, etc.)

Юнит-тест не должен:

  • Содержать какую-либо логику (if,for,while)
  • Сравнивать результат работы блока с результатом работы другого блока
  • Сравнивать результат работы блока с результатом работы некоторого алгоритма (описанного в тесте)
  • Проверять то, что не должно проверяться или должно проверяться другими (например, правильно ли работает обфускатор ассетов)
  • Тестировать слишком много - помним про максимальную атомарность. (тест "It loads history records, unserializes them and fullfill search block whith them" - повод задуматься и разбить его на много мелких)

Пример неправильного теста:

Пример правильного теста:

На данный момент в системе принято и используется 3 основных вида тестов.

Простые тесты, покрывающие тестами модули системы, пишутся для модулей, результат работы которых легко сравнить с некоторым эталонным значением. Хороший пример - модуль преобразования дат:

В простых спеках как правило используются проверки вида toEqual, toBeTruthy, toBeFalsy, toBe, not.toBe, toBeDefined, toBeUndefined, toBeLessThan, toBeGreaterThan и другие.

Асинхронные спеки предназначены для тех частей функционала, которые выполняются асинхронно. Например, если спек попытается прогнать тесты на модуле, который еще не был проинициализирован в ядре, он завершится с ошибкой. Для работы с такими ситуациями предусмотрены команды waitsFor и runs. Блоки runs, идущие друг за другом, позволяют выполнять код последовательно. Пример асинхронных тестов находится в search_history_spec.js.

Пример асинхронного спека, который ждет инициализации модуля (is_search_loaded - функция):

Спеки, основанные на фикстурах

Некоторые части функционала js-приложений в результате своей работы каким-то образом изменяют DOM. Простые спеки не помогут протестировать такой фунционал, поэтому применяют тесты основанные на фикстурах. Фикстура представляет собой html-файл, в котором содержится необходимая для теста html-разметка, например, форма с несколькими полями. Единственное допущение в случае с такими тестами - они могут содержать последовательность действий (воспроизводящую действия пользователя), на основе которой получается некоторый результат. Далее приведен пример с тестированием правильного заполнения формы:

Выделение функционала, подлежащего покрытию тестами

В системе поддерживается идея максимального сокрытия данных внутри модулей, поэтому некоторый функционал недоступен извне. В таком случае, разработчику необходимо самостоятельно сообщить ядру, какой функционал данного модуля подлежит покрытию тестами. Для этого внутри самого модуля необходимо вызвать метод test() и передать в него объект, содержащий весь необходимый функционал. Далее приведен пример из модуля L10n:

Особенности jasmine-тестов внутри текущих проектов

В силу особенностей механизма инициализации модулей, из которых состоит приложение, может получиться ситуация, когда тест на модуль будет запускаться раньше, чем инициализироваться сам модуль. Для этого введено специальное ограничение - название теста в блоке describe должно совпадать с названием тестируемого модуля:

Тесты располагаются в структуре директорий, совпадающей со структурой реального приложения:

Название файла с тестами должно совпадать с названием тестируемого модуля и содержать постфикс "_spec":

В некоторых тестах нужны данные, которых может не быть на момент запуска теста. Для этого необходимо "подождать" данные. Пример того, как тесты перед запуском ждут появления объекта search_results:

Внутри блока describe может содержаться любое количество блоков it. Блок it - функция, принимающая на вход два параметра:



Программирование на стороне клиента давно стало нормой, а объем JavaScript кода и его сложность постоянно растут. Часто тестирование применяется только на серверной стороне, но при этом не стоит забывать о тестировании клиентского кода. Для тестирования JavaScript как на стороне клиента, так и для Node.js можно с успехом применять Jasmine.

Jasmine это BDD фреймворк (Behavior-Driven Development — Разработка на Основе Поведений) для тестирования JavaScript кода, позаимствовавший многие черты из RSpec.

Для удобства, будет рассматриваться тестирование в браузере, а для лаконичности примеры приводятся с использованием CoffeeScript (примеры на JavaScript).

Установить Jasmine можно скачав пакет Jasmine standalone. Потребуются файлы:

  • lib/jasmine-*/jasmine.js — сам фреймворк
  • lib/jasmine-*/jasmine-html.js — оформление результатов в виде HTML
  • lib/jasmine-*/jasmine.css — внешний вид результата выполнения тестов
  • SpecRunner.html — файл, который следует открыть в браузере для запуска тестов

Основными ключевыми словами при работе с Jasmine являются:

  • describe — определение набора тестов, наборы могут быть вложенными
  • it — определение теста внутри любого набора тестов
  • expect — определяет ожидания, которые проверяются в тесте

Ключевые слова describe и it являются обычными вызовами функций, которым передаются два параметра. Первый — название группы или теста, второй — функция содержащая код. Простой пример для ясности:

Для того чтобы отключить выполнение набора тестов или конкретного теста, необходимо воспользоваться ключевыми словами xdescribe и xit соответственно.

Jasmine имеет стандартный набор ожиданий для проверки результатов:

Для того чтобы избежать повторения при создании/удалении объектов и загрузки фикстур, необходимых для выполнения тестов, используются функции beforeEach/afterEach. Они запускаются перед/после каждого теста в наборе.

Jasmine поддерживает тестирование асинхронных вызовов с помощью функций runs и waitsFor.

Рассмотрение работы со “шпионами” spies (mock object) и работы со временем (mock clock) оставим для следующей статьи. Если у Вас есть вопросы или замечания, буду рад на них ответить.


Karma

Karma — это консольный инструмент для запуска тестов, который умеет следить за изменениями исходного кода и отображать процент покрытия кода тестами. Настраивается с помощью конфигурационного файла karma.conf.js, в котором нужно указать пути к файлам, которые будут тестироваться, и пути к файлам, содержащие тесты.

Консольные команды

karma init — создаёт базовый шаблон файла конфигурации. Его можно также скачать с репозитория.
karma start — запуск

Jasmine

Jasmine — фреймворк для написания js-тестов.
Основной синтаксис фреймворка:
describe() — оборачивает тесты в test-suite;
beforeEach() и afterEach() — соответственно запускаются для каждого теста;
it(‘название теста’, function()<>) — сам тест;
iit() и xit() — выделяют тест, чтобы прогнать только его или игнорировать его соответственно.

Пример теста


Установка и настройка компонентов

Скачивать компоненты мы будем с помощью пакетного менеджера npm, который входит в состав Node.js. Он также необходим для работы Karma.
После установки Node.js, переходим в корень проекта, вызываем консоль и поочерёдно выполняем команды. Все скачанные компоненты будут располагаться в каталоге node_modules.

Karma

Jasmine

npm install -g jasmine

Чтобы использовать фреймворк Jasmine, подключите к проекту следующие файлы:
jasmine.js — сам фреймворк;
jasmine-html.js — оформление результатов в виде HTML;
jasmine.css — внешний вид результата выполнения тестов.

Также можно использовать следующие команды:
jasmine init — инициализирует Jasmine проект;
jasmine examples — помещает в Jasmine проект примеры с тестами.

Настройка файла конфигурации Karma

Нужно убедиться, что для Karma прописана переменная среды ОС. Создадим файл с именем karma.conf.js. Для этого нужно в консоли выполнить команду
karma init karma.conf.js.

Пример файла karma.conf.js

Пример файла karma.conf.js

Параметры karma.config.js:

В скобках () для каждого параметра указано значение по умолчанию:
files([]) — список файлов для загрузки. Массив тех файлов, которые будут подключены в браузер для запуска тестов;
exclude([]) — список исключений для предыдущего пункта;
reporters([‘progress’]) — вариант вывода прогресса;
port(8080) — порт веб-сервера;
runnerPort(9100) — порт клиента;
colors(true) — включение/выключение цветов при выводе лога в консоль;
logLevel(LOG_INFO) — LOG_DISABLE|LOG_ERROR|LOG_WARN|LOG_INFO|LOG_DEBUG;
autoWatch(false) — выполнение тестов при изменении файлов;
browsers([]) — Chrome, ChromeCanary, Firefox, Opera, Safari, PhantomJS;
captureTimeout(5000) — задание таймаута в миллисекундах;
singleRun(false) — для одноразового запуска;
preprocessors(<>) — список обработчиков, которые будут применены к файлам, до загрузки в браузер.

Мы все знаем, что должны тестировать наш код, но на самом деле мы этого не делаем. Думаю, будет справедливо сказать, что большинство из нас откладывают это, потому что в девяти случаях из десяти это означает изучение еще одной концепции. В этом руководстве я познакомлю вас с отличной небольшой платформой для простого тестирования кода JavaScript.

Например , ThemeManiac исправит ошибки JavaScript или проблемы совместимости браузера на вашем веб-сайте или в веб-приложении. Исправления могут быть выполнены очень быстро, в зависимости от сложности и доступной информации. Он также может реорганизовать ваши скрипты и создать совершенно новый пользовательский интерфейс. Он выполнил более 1000 рабочих мест в Envato Studio, и 99% клиентов рекомендуют его.

ThemeManiac на Envato Studio исправит ошибки JavaScript

Шаг 0: Понимание BDD

Сегодня мы будем изучать среду тестирования BDD Jasmine . Но сначала мы остановимся здесь, чтобы очень кратко рассказать о BDD и TDD. Если вы не знакомы с этими аббревиатурами, они означают разработку на основе поведения и разработку на основе тестирования . Я нахожусь в процессе изучения того, что каждый из них на практике и чем они отличаются, но вот некоторые из основных отличий:

BDD и TDD… означают разработку на основе поведения и разработку на основе тестирования .

TDD в простейшем виде это просто:

  1. Напишите свои тесты
  2. Смотреть их не удастся
  3. Заставь их пройти
  4. Refactor
  5. Повторение

Это довольно легко понять, а?

BDD немного более сложен: как я понимаю это прямо сейчас, я не думаю, что вы или я, как один разработчик, действительно можем практиковать это полностью; это больше командная вещь. Вот несколько практик BDD:

  • Установление целей различных заинтересованных сторон, необходимых для реализации видения
  • Вовлечение заинтересованных сторон в процесс внедрения путем разработки программного обеспечения извне
  • Использование примеров для описания поведения приложения или единиц кода
  • Автоматизация этих примеров для обеспечения быстрой обратной связи и регрессионного тестирования

Чтобы узнать больше, вы можете прочитать обширную статью в Википедии (из которой были взяты эти пункты).

Шаг 1: Изучение синтаксиса


Жасмин берет много подсказок от Rspec.

Если вы вообще знакомы с Rspec, де-факто платформой BDD, вы увидите, что Jasmine берет много подсказок от Rspec. Тесты Жасмин в основном состоят из двух частей: describe блоки и блоки. Посмотрим, как это работает.

Мы рассмотрим несколько более приближенных к реальной жизни тестов, но сейчас мы сделаем это просто:

Функции description и it принимают два параметра: текстовую строку и функцию. Большинство тестовых фреймворков стараются читать как можно больше на английском, и вы можете увидеть это с помощью Jasmine. Во-первых, обратите внимание, что строка, переданная для describe и строка, переданная it образуют предложение (своего рода): «Оператор сложения JavaScript добавляет два числа вместе». Затем мы продолжим, чтобы показать как.

Внутри этого блока вы можете написать весь код установки, необходимый для вашего теста. Нам не нужно ничего для этого простого примера. Когда вы будете готовы написать реальный тестовый код, вы начнете с функции expect , передавая все, что вы тестируете. Обратите внимание, как это также формирует предложение: мы «ожидаем, что 1 + 2 будет равно 3».

Но я забегаю вперед. Как я уже сказал, любая ценность, которую вы expect будет проверена. Метод, который вы вызываете из возвращенного значения expect , будет определяться тем, какой тест будет запущен. Эта группа методов называется «сопоставителями», и сегодня мы рассмотрим некоторые из них. В этом случае мы используем toEqual сопоставления toEqual , которое проверяет, что значение, переданное expect и значение, переданное toEqual являются toEqual и тем же значением.

Я думаю, что вы готовы перейти на следующий уровень, поэтому давайте настроим простой проект с использованием Jasmine.

Шаг 2: Настройка проекта

Жасмин может быть использован сам по себе; или вы можете интегрировать его с проектом Rails. Мы сделаем первое. В то время как Jasmine может работать вне браузера (например, Node, в других местах), мы можем получить действительно хороший маленький шаблон с загрузкой.

Итак, зайдите на отдельную страницу загрузки и получите последнюю версию. Вы должны получить что-то вроде этого:

Вы найдете актуальные файлы Jasmine Framework в папке lib . Если вы предпочитаете структурировать свои проекты по-другому, пожалуйста, сделайте это; но мы собираемся сохранить это сейчас.

Этот файл SpecRunner.html запускает тесты в браузере. Откройте его (и установите флажок «пройдено» в правом верхнем углу), и вы должны увидеть что-то вроде этого:

Образцы тестов

Это показывает нам, что все тесты для примера проекта проходят. После того, как вы spec/PlayerSpec.js этот урок, я рекомендую вам открыть файл spec/PlayerSpec.js и просмотреть этот код. Но сейчас давайте попробуем этот материал для написания теста.

  • Создайте convert.js в папке src .
  • Создайте convertSpec.js в папке spec ,
  • Скопируйте файл SpecRunner.html и переименуйте его в SpecRunner.original.html .

Удалите ссылки на файлы примеров проектов в SpecRunner.html и добавьте следующие строки:

Теперь мы готовы создать мини-библиотеку, которая будет конвертировать единицы измерения. Начнем с написания тестов для нашей мини-библиотеки.

Итак, давайте напишем наши тесты, не так ли?

Начнем с этого; мы тестируем нашу библиотеку Convert . Вы заметите, что мы здесь describe утверждения. Это совершенно законно. На самом деле это отличный способ протестировать отдельные функциональные блоки одной и той же кодовой базы. Вместо двух отдельных описательных вызовов для Convert расстояний и объемных преобразований библиотеки Convert , у нас может быть более описательный набор таких тестов.

Теперь о реальных тестах. Я повторю звонки по внутреннему describe для вашего удобства.

Вот наши тесты для преобразования расстояний. Здесь важно что-то заметить: мы еще не написали ни капли кода для нашей библиотеки Convert , поэтому в этих тестах мы делаем больше, чем просто проверяем, работает ли она: мы на самом деле решаем, как она будет использоваться. (и поэтому реализовано). Вот как мы решили сделать наши конверсии:

Да, я согласен с тем, как Jasmine реализовал свои тесты, но я думаю, что это хороший формат. Итак, в этих двух тестах я сделал преобразования самостоятельно (хорошо, с помощью калькулятора), чтобы увидеть, какими должны быть результаты наших вызовов. Мы используем сопоставление toEqual чтобы проверить, прошли ли наши тесты.

Вот тесты объема:

И я собираюсь добавить еще два теста в наш вызов describe верхнего уровня:

Они проверяют наличие ошибок, которые следует выдавать, когда неизвестные единицы передаются либо в функцию Convert либо в метод to . Вы заметите, что я оборачиваю фактическое преобразование в функцию и передаю его expect функции. Это потому, что мы не можем вызывать функцию как expect параметр; нам нужно передать ему функцию и позволить ей вызвать саму функцию. Поскольку нам нужно передать параметр в функцию, мы можем сделать это следующим образом.

toThrow вещь, на которую стоит обратить внимание, это то, что я представляю новый toThrow сопоставления: toThrow , который принимает объект ошибки. Скоро мы рассмотрим еще несколько матчей.

Теперь, если вы откроете SpecRunner.html в браузере, вы получите следующее:

Преобразовать неудачные тесты

Большой! Наши тесты не проходят. Теперь давайте откроем наш файл convert.js и поработаем:

Мы не собираемся обсуждать это, потому что мы изучаем здесь Жасмин. Но вот основные моменты:

Теперь вернитесь к SpecRunner.html и перезагрузите страницу. Теперь вы должны увидеть это (после проверки «Показать пройдено»):


Вот и вы! Наши тесты проходят. Если бы мы разрабатывали настоящий проект здесь, мы бы написали тесты для определенной части функциональности, заставили бы их пройти, написали тесты для другой проверки, сделали их проходными и т. Д. Но так как это был простой пример, мы только что сделали это все одним махом.

И теперь, когда вы увидели этот простой пример использования Jasmine, давайте рассмотрим еще несколько функций, которые он предлагает вам.

Шаг 4: Изучение соответствия

До сих пор мы использовали два сопоставителя: toEqual и toThrow . Есть, конечно, много других. Вот несколько, которые вы, вероятно, найдете полезными; Вы можете увидеть весь список в вики .

toBeDefined / toBeUndefined

Если вы просто хотите убедиться, что переменная или свойство определены, для этого есть подходящее средство. Есть также один, чтобы подтвердить, что переменная или свойство не undefined .

toBeTruthy / toBeFalsy

Если что-то должно быть правдой или ложью, эти сопоставители сделают это.

toBeLessThan / toBeGreaterThan

Для всех, кого ты числишь. Вы знаете, как они работают:

toMatch

Есть какой-нибудь выходной текст, который должен соответствовать регулярному выражению? Матч toMatch готов и готов.

содержать

Этот довольно полезен. Он проверяет, содержит ли массив или строка элемент или подстроку.

Есть также несколько других совпадений, которые вы можете найти в вики . Но что, если вы хотите совпадения, которого не существует? В самом деле, вы должны иметь возможность делать что угодно с некоторым кодом настройки и средствами сопоставления, которые предлагает Jasmine, но иногда лучше абстрагировать часть этой логики, чтобы сделать тест более читабельным. По счастливой случайности (ну, на самом деле нет), Жасмин позволяет нам создавать наших собственных сопоставителей. Но для этого нам нужно сначала немного научиться чему-то другому.

Шаг 5: Покрытие до и после

Часто при тестировании кодовой базы вам нужно выполнить несколько строк кода настройки для каждого теста в серии. Было бы больно и многословно копировать это при каждом вызове, поэтому у Jasmine есть небольшая удобная функция, которая позволяет нам назначать код для запуска до или после каждого теста. Давайте посмотрим, как это работает:

В этом надуманном примере вы можете видеть, как перед каждым тестом состояние obj устанавливается в «clean». Если мы этого не сделали, то изменения, внесенные в объект в предыдущем тесте, сохраняются в следующем тесте по умолчанию. Конечно, мы могли бы сделать нечто подобное с функцией AfterEach :

Здесь мы настраиваем объект для начала, а затем корректируем его после каждого теста. Если вам нужна функция MyObject чтобы вы могли попробовать этот код, вы можете получить ее здесь, в GitHub .

Шаг 6: Написание пользовательских соответствий

Как мы уже говорили ранее, клиенты, вероятно, будут полезны время от времени. Итак, давайте напишем один. Мы можем добавить сопоставление в вызове BeforeEach или вызове it (ну, я думаю, вы могли бы сделать это в вызове AfterEach , но это не имело бы особого смысла). Вот как вы начинаете:

Довольно просто, а? Мы вызываем this.addMatchers , передавая ему объектный параметр. Каждый ключ в этом объекте станет именем сопоставителя, и связанная с ним функция (значение) будет определять способ его запуска. Допустим, мы хотим создать сопоставление с проверкой, чтобы увидеть, находится ли одно число между двумя другими. Вот что вы написали бы:

Мы просто берем два параметра, проверяем, что первый меньше второго, и возвращаем логическое выражение, которое оценивается как true, если наши условия выполнены. Здесь важно отметить, как мы получаем значение, которое было передано expect функции: this.actual .

Это то, что SpecHelper.js файл SpecHelper.js ; у него есть вызов beforeEach который добавляет tobePlaying() . Проверьте это!

Вывод: развлекайся сам!

С Jasmine вы можете сделать гораздо больше: сопоставители функций, шпионы, асинхронные спецификации и многое другое. Я рекомендую вам изучить вики, если вам интересно. Есть также несколько сопутствующих библиотек, которые облегчают тестирование в DOM: Jasmine-jQuery и Jasmine-fixture (зависит от Jasmine-jQuery).

Так что, если вы пока не тестируете свой JavaScript, самое время начать. Как мы уже видели, быстрый и простой синтаксис Jasmine делает тестирование довольно простым. У тебя просто нет причин не делать этого сейчас, не так ли?

Если вы хотите продолжить разработку JavaScript, почему бы не проверить ассортимент элементов JavaScript на Envato Market? Существуют тысячи сценариев, приложений и фрагментов кода, чтобы помочь вам.

Stepan Suvorov Blog

Jasmine на данный момент одна из самым популярных библиотек для организации юнит тестирования JavaScript.

Первым делом скачиваем себе библиотеку с офсайта. Далее создаем себе песочницу для экспериментов. Вместе с библиотекой сразу идет пример использования, но возможно сходу разобраться в нем будет не просто. Более простая версия будет выглядеть так:

Сразу модуль для рендера результатов(jasmine-html.js) и подключим его. Итоговый код будет такой:

Песочница есть, теперь можем переходить к экспериментам в tests.js:

* describe может включать в себя другой describe (если нужны подсекции)

далее идет сам тест:

понятное дело, что вместо true тут будет 2 выражения, которые должны быть равны. Какие еще могут быть варианты для сравнения?

Также возможны варианты для нахождение совпадений подстроки:

Либо нахождения свойства в объекте:

Варианты проверки null и undefinded:

Аналогично работают методы: toBeTruthy, toBeFalsy, toContain(проверяет наличие значение в массиве), toBeLessThan, toBeGreaterThan, toBeCloseTo.

Если мы захотим проверить имя класса конструктора( аналог instanceof):

Также есть метод проверки исключений:

В группе тестов мы можем использовать инструкции beforeEach и afterEach, в которых мы указываем что нужно выполнить до/после каждого теста:

Группы и тесты обладают интересной особенностью, если мы поставим перед describe или it символ x, т.е. xdescribe и xit, то они будут проигнорированы. (При этом ошибка о том, что метод не найден, вызвана не будет)

Еще с помощью Jasmine мы можем выставлять наблюдателей(observer) на разные объекты с помощью метода spyOn:

После чего станут доступны следующие проверки:

Для метода spyOn существует ряд надстроек:

и более сложные:

В случае, когда мы должны произвести тест через некоторое время после запуска тестируемого кода, на помощь нам приходит метод jasmine.Clock( аналог setTimeOut):

Теперь напишем тест для него:

Метод waitsFor имеет следующий синтаксис:

Итак еще раз: мы помещаем наши асинхронные действия в метод runs() и при выполнении этого действия меняем флаг, а в waitsFor() помещаем функцию, которая будет возвращать этот самый флаг. Причем тут может быть как один флаг, так и гораздо более сложные проверки (например, если у нас идет несколько асинхронных вызовов).

Читайте также: