Автотесты «на пальцах»
Что и как тестировать у модуля
Интеграционные тесты
Автотесты «на пальцах»
Что и как тестировать у модуля
Интеграционные тесты
Модули — это функции, классы, модели, контроллеры — кирпичики, из которых построено приложение.
Что тестировать?
У модулей есть публичный интерфейс, через который с ними работают другие модули. Если представить, что модуль — это машина, то её публичный интерфейс — это функции доступные водителю: «ехать прямо», «повернуть налево», «включить радио».
Публичный интерфейс использует приватные функции, доступные только самому модулю. В случае с машиной — это всё, что скрыто под капотом: «скорректировать угол опережения зажигания» или «поднять давление в топливной рампе».
Приватные функции постоянно меняются, переименовываются и исчезают, публичные функции меняются редко. Так в Тесле уже нет ни зажигания, ни топливной рампы, а функции «повернуть налево» и «включить радио» на месте.
Рекомендуем проверять модульными тестами не приватные функции, а только публичный интерфейс. Во‑первых, тесты публичного интерфейса так или иначе проверят приватные функции, которые он использует. Во‑вторых, тесты публичного интерфейса служат документацией: мы видим, как правильно и неправильно использовать тестируемый модуль. В‑третьих, такие тесты проще поддерживать: при рефакторинге изменения в приватных функциях не будут ломать тесты.
Как тестировать?
Функции можно разделить на два типа: запросы и команды. Запросы возвращают что‑то и ничего не меняют: user.isEditor()
, array.find()
, spread.isOnScreen()
. Команды что‑то меняют и, бывает, что‑то возвращают: user.destroy()
, array.splice()
, spread.delete()
.
Чтобы убедиться, что функция‑запрос работает правильно, проверьте то, что она возвращает:
В примерах используется Jest — фреймворк для тестирования приложений на Яваскрипте
// Проверим функцию, которая из имени автора совета
// выделяет фамилию и возвращает её в родительном падеже
//
// С помощью describe задают структуру теста: что тестируем и в каких условиях
describe('#genitiveFamilyName', () => {
describe('with initials', () => {
// С помощью it описывают ожидания от кода
it('returns it as is', () => {
// С помощью expect сверяют ожидания с реальностью:
// если они не совпадут, тестовый фреймворк покажет ошибку
expect(genitiveFamilyName('А. Г.')).toEqual('А. Г.')
})
})
it('returns surname in genitive form', () => {
expect(genitiveFamilyName('Максим Ильяхов')).toEqual('Ильяхова')
})
it('returns surname in genitive form for female names', () => {
expect(genitiveFamilyName('Таня Бибикова')).toEqual('Бибиковой')
})
})
В примерах используется Jest — фреймворк для тестирования приложений на Яваскрипте
Чтобы убедиться, что функция‑команда работает правильно, проверьте последствия её вызова:
Мы не случайно отбиваем пустыми строками куски кода. Так отделяют фазы теста: настройку, испытание и проверку. Подробнее расскажу о них в следующих советах
// Проверим функцию, которая модифицирует ДОМ-дерево,
// пронумеровывая и размечая якоря
describe('#morph', () => {
it('marks empty anchors as .is__blank so we can ignore them in navigation', () => {
const html = `<div class="anchor"></div>`
const $ = cheerio.load(html)
morph($)
expect($('.anchor').attr('class')).toContain('is__blank')
})
it('enumerates them', () => {
const html = `
<div class="anchor">One</div>
<div class="anchor">Two</div>
<div class="anchor">Three</div>
`
const $ = cheerio.load(html)
morph($)
const anchorIds = $('.anchor').get().map(el => el.id)
expect(anchorIds).toEqual(['anchor-1', 'anchor-2', 'anchor-3'])
})
})
Мы не случайно отбиваем пустыми строками куски кода. Так отделяют фазы теста: настройку, испытание и проверку. Подробнее расскажу о них в следующих советах
Ещё по теме
P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.