Введение в Jasmine

  • Tutorial

Программирование на стороне клиента давно стало нормой, а объем 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 являются обычными вызовами функций, которым передаются два параметра. Первый — название группы или теста, второй — функция содержащая код. Простой пример для ясности:

describe "Набор тестов", ->
  it "проверка ожиданий", ->
    expect(1 + 2).toBe(3)


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

describe "Отключение", ->
  xdescribe "отключенный набор тестов", ->
    it "тест не будет запущен, так как набор отключен", ->
      expect(true).toBe(true)
  xit "отключеный тест", ->
    expect(true).toBe(true)


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

  it "сравнение с использованием ===", ->
    expect(1 + 2).toBe(3)

  it "сравнение переменных и объектов (включая содержимое)", ->
    a = {x: 8, y: 9}
    b = {x: 8, y: 9}
    expect(a).toEqual(b)
    expect(a).not.toBe(b) # отрицание - a не является b

  it "значение должно быть определено", ->
    expect(window.document).toBeDefined()

  it "значение должно быть не определено", ->
    expect(window.notExists).toBeUndefined()

  it "значение должно быть null", ->
    a = null
    expect(a).toBeNull()

  it "значение должно быть верно", ->
    expect(5 > 0).toBeTruthy()

  it "значение должно быть не верно", ->
    expect(5 < 0).toBeFalsy()

  it "значение должно быть меньше чем", ->
    expect(1 + 2).toBeLessThan(5)

  it "значение должно быть больше чем", ->
    expect(1 + 2).toBeGreaterThan(0)

  it "значение должно быть близко к числу", ->
    expect(1.2345).toBeCloseTo(1.2, 1)

  it "значение должно соответствовать регулярному выражению", ->
    expect("some string").toMatch(/string/)

  it "значение должно содержать", ->
    expect([1, 2, 3]).toContain(2)
    expect("some string").toContain("some")

  it "должно быть вызвано исключение", ->
    func = -> window.notExists.value
    expect(func).toThrow()


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

describe "Подготовка/чистка", ->
  val = 0 # определение переменной в зоне видимости набора тестов

  beforeEach ->
    val += 1

  afterEach ->
    val = 0

  it "использует val", ->
    expect(val).toEqual(1)


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

  • runs — принимает асинхронную функцию для выполнения.
  • waitsFor — принимает первым параметром функцию, которая должна вернуть true, если асинхронный вызов сделанный в runs был выполнен, второй параметр — сообщение об ошибке, третий — время ожидания в миллисекундах.


  describe "Асинхронно", ->
    a = 0

  async = ->
    setTimeout((-> a = 5), 1000)

  it "асинхронное выполнение кода", ->
    runs(-> async())
    waitsFor((-> a == 5), "значение должно быть изменено", 3000)


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

Вторая часть: «Jasmine — дополнительные возможности»

Ссылки:
github.com/pivotal/jasmine — страница Jasmine на GitHub
www.inexfinance.com/en/blog/2013/1/25/jasmine_for_clientside_testing — английский вариант статьи
github.com/inex-finance/blog-examples/tree/master/jasmine — примеры кода из данной статьи

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 10

    0
    Хоть обзор и короткий, но могу подтвердить что Jasmine — классная штука.

    Классно то, что JS — динамический язык, и можно добавлять свои функции проверки ожиданий (matchers).

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

    Использовали для Windows 8 приложений для WinJS и нашли старнный баг — при отладке тестов (у нас их было около 2000), движок часто зависает. Но при запуске без отладки — всё отлично. Разбираться не стали.

    Ну и если спецификация к тесту (describe) описана в стиле «как пользователь, я ожидаю» (а не «этот код делает это»), то вообще просто ориентироваться в коде приложения, когда тест проваливается.
      +1
      А как он в сравнении с Mocha?
        +1
        Mocha более гибкий чем jasmine. Однако для mocha необходимо использование библиотеки утверждений (к примеру chai), что несколько сложнее в настройке и поддержке. Для jasmine есть прекрасный jasmine-jquery плагин, который упрощает тестирование JQuery и предоставляет поддержку фикстур. Думаю тут больше вопрос вкуса, так как по возможностям они сопоставимы.
          +1
          Ну на счет сложности настройки библиотеки утверждений(assertion library) Вы по-моему перегибаете. Chai подключается одной строчкой(как на клиенте, так и на сервере). Кроме того тот-же Chai реализует несколько стилей assertions: assert, expect, should.
          Что же касается Mocha — она реализует замечательный механизм для тестирования асинхронных методов, без использования тайм-аутов: callback done(). Все что нужно — передать done в асинхронный метод и вызвать его по окончании работы метода.
           it('should save without error', function(done){
                var user = new User('Luna');
                user.save(function(err){
                  if (err) throw err;
                  done();
                });
              })
          

          Данный подход не встречал ни у одного другого тест фреймворка для JS. Хотя данная фича на клиенте не так уж и важна, зато для ноды — самое то.
              0
              Хотя данная фича на клиенте не так уж и важна, зато для ноды — самое то

              Это смотря какой код на клиенте. Там тоже очень может пригодится асинхронный вараинт.
              Особено хорош Mocha в CoffeeScript нотации :)
          0
          Спасибо за статью. Пользовался Jasmine для тестирования Backbone и Ember моделей.
          Очень хочу пользоваться для тестирования всего приложения, но не знаю как.
          Да хорошо-приятно, что есть jasmine-jquery, но хотелось бы реальный пример тестирования.
            0
            Постараюсь в одной из следующих статей посвященной jasmine привести пример тестирования небольшого Backbone приложения.
            0
            Использую vows вместе с grunt – доволен до жути. Нотация в виде json как-то более приятна и понятна, чем набор функций, которые надо знать и помнить.
              0
              Jasmine еще очень удобно использовать вместе с jsTestDriver внутри WebStorm для тестирования клиентского кода. Ничего кроме jasmine-jstd-adapter не нужно

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое