Jasmine — дополнительные возможности

от автора

Данная статья является продолжением первой части «Введение в Jasmine». Здесь рассматриваются дополнительные возможности тестового фреймворка Jasmine, а именно:

  • Spy — эмуляция функций/объектов
  • Clock — синхронизация вызовов при использовании setTimeout/setInterval
  • Runner и Reporter — запуск тестов и оформление отчета

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

В Jasmine отслеживания вызова функции и параметров вызова осуществляется с помощью spyOn. Функции spyOn передается два параметра — объект, для которого осуществляется вызов функции, и имя функции, которую необходимо отслеживать:

  spyOn(window, 'isNaN') 

При обычном использовании spyOn вызов оригинальной функции не производится.

Примеры приведены с использованием небольшого класса Person:

class Person  name: null  age:  0  constructor: (@name, @age) ->  getName: -> @name  setName: (value) -> @name = value  getAge: -> @age  addYear: -> @age += 1 

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

describe "Spy", ->  person = null   beforeEach ->    person = new Person("Jim", 25)   it "осуществлен вызов функции", ->    spyOn(person, 'getName')    person.getName()    expect(person.getName).toHaveBeenCalled()   it "проверка количества вызовов", ->    spyOn(person, 'addYear')    person.addYear()    person.addYear()    expect(person.addYear.calls.length).toEqual(2)   it "проверка аргументов", ->    spyOn(person, 'setName')    person.setName("Ira")    expect(person.setName).toHaveBeenCalledWith("Ira") # может быть несколько аргументов      it "есть доступ к последнему вызову", ->    spyOn(person, 'setName')    person.setName("Ira")    expect(person.setName.mostRecentCall.args[0]).toEqual("Ira")   it "есть доступ ко всем вызовам", ->    spyOn(person, 'setName')    person.setName("Ira")    expect(person.setName.calls[0].args[0]).toEqual("Ira") 

При использовании spyOn вместе с andCallThrough, будет осуществлен вызов оригинальной функции:

 it "вызывает оригинальную функцию", ->    spyOn(person, 'getName').andCallThrough()    expect(person.getName()).toEqual("Jim")    expect(person.getName).toHaveBeenCalled() 

Если необходимо возвращать из функции определенное значение, то для этого надо вызвать spyOn вместе с andReturn:

 it "возвращает указанное значение", ->    spyOn(person, 'getName').andReturn("Dan")    expect(person.getName()).toEqual("Dan")    expect(person.getName).toHaveBeenCalled() 

При использовании spyOn вместе с andCallFake, вместо вызова оригинальной функции, будет вызвана указанная функция:

 it "вызывает указанную функцию", ->    spyOn(person, 'getAge').andCallFake(-> return 5 * 11)    expect(person.getAge()).toEqual(55)    expect(person.getAge).toHaveBeenCalled() 

Для создания функции без реализации можно воспользоваться createSpy, при этом доступны все возможности для тестирования обычного spy. Единственный параметр, который принимает createSpy — это имя функции для идентификации.

 it "создает фальшивую функцию", ->    concat = jasmine.createSpy('CONCAT')    concat("one", "two")    expect(concat.identity).toEqual('CONCAT') # есть имя для идентификации    expect(concat).toHaveBeenCalledWith("one", "two")    expect(concat.calls.length).toEqual(1) 

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

 it "создает фальшивый объект", ->    button = jasmine.createSpyObj('BUTTON', ['click', 'setTitle', 'getTitle'])    button.click()    button.setTitle("Help")    expect(button.click).toBeDefined()    expect(button.click).toHaveBeenCalled()    expect(button.setTitle).toHaveBeenCalledWith("Help")    expect(button.getTitle).not.toHaveBeenCalled() 

Проверка типа объекта осуществляется вызовом jasmine.any, которому передается ожидаемый тип:

 it "проверяет тип", ->    spyOn(person, 'setName')    person.setName("Ira")    expect(person.setName).toHaveBeenCalledWith(jasmine.any(String)) 

Синхронное тестирование вызовов setTimeout/setInterval осуществляется с помощью jasmine.Clock.useMock. Для перемещения времени вперед используется вызов jasmine.Clock.tick, которому передается время в миллисекундах:

describe "Время", ->  callback = null    beforeEach ->    callback = jasmine.createSpy('TIMER')    jasmine.Clock.useMock()      it "вызывает timeout синхронно", ->    setTimeout((-> callback()), 100) # задержка вызова в 100ms    expect(callback).not.toHaveBeenCalled()    jasmine.Clock.tick(101) # передвинуть время на 101ms    expect(callback).toHaveBeenCalled() 

Для запуска тестов в Jasmine, как правило, используется небольшой скрипт:

# Выполнение тестов jasmineEnv = jasmine.getEnv() jasmineEnv.updateInterval = 250 currentWindowOnload = window.onload  window.onload = ->  currentWindowOnload() if currentWindowOnload  execJasmine()  execJasmine = -> jasmineEnv.execute()  # Вид отчета htmlReporter = new jasmine.HtmlReporter() jasmineEnv.addReporter(htmlReporter) jasmineEnv.specFilter = (spec) -> htmlReporter.specFilter(spec) 

Jasmine поддерживает несколько типов отчетов о прохождении тестов, основными из них являются:

  • HtmlReporter — древовидная структура с прогрессом выполнения
  • TrivialReporter — простая древовидная структура (помечен как устаревший)
  • ConsoleReporter — вывод результатов тестирования в консоль (для node.js)

Если у Вас есть вопросы или замечания, буду рад на них ответить.

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

ссылка на оригинал статьи http://habrahabr.ru/post/169699/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *