Про юнит тестирование JavaScript

В личке спросили про автоматизацию тестирования с помощью javascript. Первая часть ответа - про юнит тестирование.

Юнит тестирование (unit testing) или модульное тестирование javascript.

Задача функционального тестирования в том, чтобы убедиться что отдельные части программы работают так как запланировано. Такое тестирование ставится наравне с написанием кода продукта при TDD (test driven development) подходе. Грубо говоря, TDD - разработка программы так, что сначала пишутся тесты модулей программы, и только потом реализуются сами модули. Обычно и тесты и код пишут программисты (т.е. специальный человек не выделяется под эту задачу), единственное что стараются не ставить одного и того же человека писать и тест и модуль чтобы исключить фактор “подыгрывания себе”. Функциональные тесты могут писать после реализации модуля, например перед рефакторингом (изменение внутренней реализации без изменений внешнего поведения).

Сетап для тестов (настройка) состоит из нескольких условных частей

Test runner

Программа (вернее npm модуль), которая запускает тесты, следит за порядком выполнения тестов, перезапускает тесты при изменении файлов, позволяет запустить часть из описанных тестов, предоставляет API для подключения расширений для процесса тестирования (например code coverage reporter). Примеры test runner-ов - https://mochajs.org, http://karma-runner.github.io/0.13/index.html. Эта программа является точкой входа при запуске тестов. Обычно стремятся организовать тесты так, чтобы их можно было запускать как с машины разработчика так и на CI (continious integration) сервере (обычно это линукс).

Обычно в конфигурации test runner-а описываются какие файлы являются файлами тестов (например все, подходящие под маске *.test.js).

Фреймворк для описания тестов

Фреймворк задает набор правил в рамках которого надо описывать тесты (например определяет как сигнализировать фреймворку о том что асинхронный тест завершился). Пример правил, которые задает фреймворк

describe('Dispatcher test suite', function () {
	var dispatcher;
	beforeEach(function () {
		dispatcher = new Dispatcher();
	})

	it('Basic event usage', function () {
		var a = 10
		dispatcher.subscribe('event', function () {
			a = 20
		})
		dispatcher.trigger('event')
		expect(a).toBe(20)
		dispatcher.subscribe('event', function () {
			a = 30
		})
		dispatcher.trigger('event')
		expect(a).toBe(30)
	})

	it('Async test example', function (done) {
		setTimeout(function () {
			done()
		}, 1000)
	})
})

функции describe и it предоставляются фреймверком, и требуют чтобы группы тестов были объединены с помощью describe, а сам отдельный тест должен быть описан в it. Если хотите выполнить код перед каждым тестом, передайте функцию в beforeEach, а чтобы сигнализировать фреймверку что асинхронный тест завершился, объявите функцию теста с аргументом. В этот аргумент будет передана функция, которую надо выполнить по завершению теста (смотри тест ’Async test example’). Пример фреймворков https://mochajs.org, http://jasmine.github.io. Некоторые решения покрывают часть спектра потребностей сетапа для тестов, предоставляя как интерфейс для тестов, test-runner, и другие части сетапа для тестирования. Поэтому вы будете видеть одни и те же названия решений при описании разных

Assertion library

Библиотека для описания предположений внутри теста. Например http://jasmine.github.io, https://github.com/shouldjs/should.js, http://chaijs.com/. Тесты устроены таким образом, что если тест при запуске выбрасывает исключение, тест считается проваленным. Assertion library - это обертка, которая упрощает выбрасывание исключений при сравнении ожидаемого результата поведения кода с реальным.
Пример использования assertion library jasmine фреймверка (подготовительный код опущен):

var a = 10
dispatcher.subscribe('event', function () {
	a = 20
})
dispatcher.trigger('event')
expect(a).toBe(20)

Такой тест будет считаться успешным если в переменной a будет храниться значение 20. Имея такой тест, я могу быть уверенным в протестированной функциональности когда в следующий раз буду вносить изменения в модуль dispatcher.

Test reporter

Часть test-runner-а, которая отвечает за отображение результатов тестов. Результаты тестов могут быть отображены в IDE, прямо в консоли или в html-ой странице с инфографикой.

О личном опыте:

На работе я использую jasmine + karma, тесты запускаются в phantomjs. Такая сборка была выбрана потому что я хочу тестировать DOM, а для этого тесты надо запускать в браузере. А так же я хотел запускать тесты на CI, поэтому тесты открываются в phantomjs (браузер без видимых окон, еще называют headless browser). + к karma легко прикручиваются препроцессоры (webpack, coverage) и разные репортеры.

В домашних проектах это mocha + https://github.com/LearnBoost/expect.js + BDD интерес тестов, если тестировать DOM не надо. Иначе это jasmine+karma. Пример сетапа karma+Jasmine можно посмотреть https://github.com/podgorniy/dispatcher

8 симпатий

Круто, спасибо, на работе использую karma+jasmine.

Напиши еще про TDD ;)

Уверен будет полезно)

Я про TDD знаю только по наслышке. Мне нечем поделиться по этой теме.

Надеюсь в тему — понравилось использовать Tape, очень простой в применении

Вот пример игры “Крестики нолики” (Webpack + React + ES6 + Tape + Enzyme)
Исходный код на GitHub и покрыт тестами