Тестирование. Юнит-тесты.
Добавлено: Вт, 24 ноября 2015, 11:43:09
JavaScript QUnit
http://habrahabr.ru/post/83170/
http://habrahabr.ru/post/83170/
- Спойлер
- QUnit. Тестирование javascript кода
JavaScript*
Наткнулся вчера на этот инструмент и не смог пройти мимо, провел ночь за написанием тестов, а теперь хочу поделиться находкой. QUnit — это библиотека от разработчиков jQuery, позволяющая писать unit-тесты для кода на javascript. Удобна в использовании, ничего лишнего, осваивается за 20 минут, выгода от применения — колоссальная.
Самым нетерпеливым сразу ссылки:
Официальная документация на сайте jquery: docs.jquery.com/QUnit
Реальные примеры тестов (для модулей jquery): view.jquery.com/trunk/jquery/test/unit/
Руководство для начинающих (англ): www.swift-lizard.com/2009/11/24/test-driven-development-with-jquery-qunit/
Система распределенного тестирования (гениально и просто): testswarm.com/
Под катом информация о преимуществах юнит-тестирования применительно к js и разбор возможностей библиотеки на примерах.
Зачем писать unit-тесты?
Представим себе обычный цикл разработки: получили задачу, решили её, протестировали, починили баги и выпустили версию. Затем получили баг-репорты и фиче-реквесты и приступили к новому циклу разработки. По завершению этого цикла нам снова надо будет проверить, что всё то, что было реализовано ранее, по прежнему работает — провести регрессионное тестирование. И проводить его надо будет для каждого нового цикла разработки. По мере разрастания проекта на это будет уходить всё больше и больше времени. А как происходит регрессионное тестирование в web-проектах? Кликаем мышкой по кнопкам и ссылкам. В каждом браузере, для каждой фичи, на каждом цикле разработки. Нашли баг, поправили, обновляем страницу и снова кликаем, кликаем, кликаем.
Юнит тесты позволяют эту рутину автоматизировать. При реализации фичи параллельно пишутся тесты, которые проверяют правильность её функционирования, багов в процессе разработки будет сразу меньше. При нахождении ошибки, если тест не покрывал ее ранее, пишется новый тест, который зафиксирует ошибку формально и впредь никогда её не пропустит. Даже если в будущем что-то пойдет не так — тест сразу покажет ошибки, ещё до того как программа попадет в руки тестировщиков.
Касательно web-разработки есть ещё одно огромное преимущество — запуск тестов под разными платформами и браузерами. Больше нет нужды проверять дотошно, как этот кусок кода будет работать в msie, понравится ли он опере, а как к нему отнесется сафари. Достаточно написать тест, который проверит функциональность. Более того, эту работу можно распределить между обычными пользователями, хороший пример такой функциональности — testswarm.com.
Как использовать QUnit
Это очень просто: понядобятся два файла:
QUnit.js и QUnit.css, а также новый html документ примерно такого содержания:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="qunit.css" type="text/css" media="screen">
<script type="text/javascript" src="qunit.js"></script>
<script type="text/javascript" src="your-code-for-testing.js"></script>
<script type="text/javascript" src="your-tests.js"></script>
</script>
</head>
<body>
<h1 id="qunit-header">QUnit test env</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests">
</ol>
</body>
</html>
* This source code was highlighted with Source Code Highlighter.
Теперь подключаем свой код и можно писать тесты.
Как писать тесты
Это проще чем кажется. Давайте протестируем функцию trim, которая удаляет пробелы и табы на концах строки. Вот её код:
function trim(text) {
return (text || "").replace(/^\s+|\s+$/g, "");
}
* This source code was highlighted with Source Code Highlighter.
А вот так её можно протестировать:
test('trim()', function () {
equals(trim(''), '', 'Пустая строка');
ok(trim(' ') === '', 'Строка из пробельных символов');
same(trim(), '', 'Без параметра');
equals(trim(' x'), 'x', 'Начальные пробелы');
equals(trim('x '), 'x', 'Концевые пробелы');
equals(trim(' x '), 'x', 'Пробелы с обоих концов');
equals(trim(' x '), 'x', 'Табы');
equals(trim(' x y '), 'x y', 'Табы и пробелы внутри строки не трогаем');
});
* This source code was highlighted with Source Code Highlighter.
Разберем пример построчно. В первой строке вызов функции test. Первым параметром обозначаем функционал который тестируем. Последним — тестирующую функцию. Внутри этой функции производятся различные проверки. В данном случае мы проверяем соответствие результата выполнения функции и ожидаемой строки. Для проверки на соответствие используются функции:
equals — проверяет равенство первых двух параметров (нестрогая проверка, только для скалярных величин)
ok — истинность первого параметра
same — строгая проверка на равенство первых двух параметров (проверяет также равенство двух массивов и объектов)
Последним параметром функции принимают описание тестового случая.
В результате этой проверки получаем следующую картину:
Все тесты пройдены.
Как протестировать ajax? Асинхронные проверки.
С синхронными функциями просто. А что с асинхронными? Очевидно, для асинхронности мы должны остановить нормальный поток управления и по окончанию теста возобновить его. Этому служат функции stop() и start(). Вот простой пример:
test('async', function () {
// Останавливаем поток выполнения на этом тесте
stop();
setTimeout(function () {
ok(true);
// По завершению теста
// возобновляем работу тестировщика
start();
}, 500);
});
* This source code was highlighted with Source Code Highlighter.
Чтобы не вызывать всякий раз stop(); предусмотрен следующий вариант функции:
asyncTest('async', function () {
// поток остановлен автоматически
setTimeout(function () {
ok(true);
// Возобновляем конечно же вручную
start();
}, 500);
});
* This source code was highlighted with Source Code Highlighter.
А что если надо вызвать несколько асинхронных проверок в одном тесте? Когда в этом случае «стартовать» поток? Решение предлагается такое:
asyncTest('asynctest', function () {
// Pause the test
expect(3);
$.get(function () {
// асинхронные проверки
ok(true);
});
$.get(function () {
// другие асинхронные проверки
ok(true);
ok(true);
});
setTimeout(function () {
start();
}, 2000);
});
* This source code was highlighted with Source Code Highlighter.
Поток стартуется через 2 секунды. За это время должны пройти три проверки (вызов expect сообщает об этом тестирующей программе). Кстати, вместо вызова expect можно передавать второй числовой параметр функции test (asyncTest). Поведение будет идентичным предыдущему примеру.
Группировка тестов по модулям
QUnit позволяет сгруппировать тесты по модулям. Для этого достаточно вызвать функцию module('Название модуля или группы тестов') непосредственно перед вызовом тестов. Это удобно.
Резюме
Вот, в принципе и всё что нужно для того, чтобы начать тестировать свой код в автоматическом режиме. За дополнительной информацией обращаться сюда: docs.jquery.com/QUnit
Очень хорошие примеры тестов можно найти здесь (это тесты для core jquery).
Спасибо за внимание.
javascript, tdd, test driven development, qunit, testswarm, unit testing
+65
31,3к
336
Чаккаев Анатолий @1602 карма119,9 рейтинг0,0
Похожие публикации
+14
Real-life unit tests 3,5к 52 50
+12
Избирательное юнит-тестирование или ещё раз о тонких контроллерах 1,7к 34 11
+107
Анти-паттерны Test Driven Development 6,9к 174 64
Самое читаемое
Сейчас Неделя Месяц
Управление вещами реального мира из виртуального мира Minecraft (перевод) 10
Релиз Android Studio 2.0: две убер-фичи 10
Первый в мире плавучий дата-центр спустили на воду 16
Superfish: возвращение 16
Как мы проектируем и прототипируем всякую фигню 34
400 потрясающих бесплатных сервисов 29
Жизнь PHP-разработчика 234
Анализ резюме с HeadHunter. Кто сколько зарабатывает и в каких отраслях работает 55
Инфраструктура и торговые роботы: Какие языки программирования используются в сфере финансов 5
Декларативное программирование на C++ 2
Вопросы по теме
Как отсортировать массив объектов JS? 1
Как сделать подгрузку из сети в Cordova? 1
Каким JQuery плагином увеличит картинку до 95% экрана? 1
Пробки на дорогах, как можно сделать информер баллов? 1
Есть ли возможность сделать мобильное веб-приложение с уведомлениями? 1
Комментарии (22)
–6 neformal 5 февраля 2010 в 10:28#
Ну наконец то на Хабре опубликовали полезный пост.
Спасибо.
+2 rigid 5 февраля 2010 в 10:32#
спасибо за статью. в закладки одноззначно
+2 vovich 5 февраля 2010 в 10:41#
а где можно почитать побольше про юнит тесты? у меня возникла проблема с ними — на этапе разработки слишком много времени уходит на написание фикстур и т.д. Как правильно пользовать юнит тесты в условиях быстро меняющихся условий?
+2 etl 5 февраля 2010 в 10:46#↵↑
JS Ninja — как раз ничанается с концепции юниттестов.
0 Aralot 5 февраля 2010 в 11:20#↵↑
а скажите кто-нибудь внятно — она уже вышла?
+1 etl 5 февраля 2010 в 13:11#↵↑
Preorder)) www.manning.com/resig/
0 keith 5 февраля 2010 в 11:05#↵↑
хороший вопрос.
в процессе работы над очередной версией компонента/проекта имеет смысл писать тесты на неизменяемый функционал — отправка письма, доступ к данным и сервисам.
бизнес-логику, которая сильно подвержена изменениям лучше покрывать тестами выборочно и ближе к концу текущей версии.
если бизнес-логика сильно меняется от версии к версии, то тут надо решить что важнее — время разработки или стабильность релизов, хотя чаще всего можно найти компромис.
0 vovich 5 февраля 2010 в 11:19#↵↑
А есть ли смысл тратить время, покрывая юнит тестами мелкий функционал, особенно отправку писем. Это достаточно просто проверяется и врядли сломается. А вот как раз бизнес логика, где полно связаных компонентов, вот тут и возникают проблемы, с тем, что после изменений система работает, но с ошибкой. Из моего опыта чаще всего появляются баги:
1) верстка — тут уж только визуально, заодно и тестирование функционала
2)SQl скрипты — из за ошибки в скрипте берутся либо не те данные, либо не в правильном порядке, либо сохраняются нетуда, ХЗ как такое проверить и протестировать
3) Логика — чаще всего в операторах IF и switch. тут как раз, как я понимаю, и помогут юнит тесты.
4) плохие входные данные — тут опять же помогут юнит тесты.
+2 lomik 5 февраля 2010 в 12:39#↵↑
> 2)SQl скрипты — из за ошибки в скрипте берутся либо не те данные, либо не в правильном порядке, либо сохраняются нетуда, ХЗ как такое проверить и протестировать
А в чем проблема? При запуске тестов создается временная база данных, заполняется тестовыми данными и проверяется работоспособность. По окончании база грохается.
0 keith 5 февраля 2010 в 14:53#↵↑
я говорил не про мелкий функционал, а про неизменяемый. отправка письма в интернет-магазине является критичным функционалом и может отваливаться когда захочет.
про верстку говорить не буду — с ней все понятно.
про доступ к данным я упомянул — я создаю тестовую БД и на ней тестирую.
логику — ближе к концу итерации. только логика — это не if и switch
валидация — само собой.
+2 lomik 5 февраля 2010 в 12:46#↵↑
Кстати по поводу правильного использования. Один из методов — разработка через тестирование. По ссылке все достаточно коротко и понятно написано.
0 1602 5 февраля 2010 в 22:35#↵↑
Да, согласен с Вами, писать тесты до самого функциональности — хорошая практика. К сожалению, не всегда получается применить в жизни.
0 lomik 5 февраля 2010 в 22:41#↵↑
Могу даже уточнить — практически никогда не получается. Сам применяю только когда пишу для себя — медленно, аккуратно и без меняющегося непрерывно ТЗ. Зато как потом работает и удобство по добавлению новых функций/исправлению багов выше всяких похвал.
Но даже когда не получается этот метод использовать хорошо о нем помнить. Всегда можно написать таким методом не весь код, а только «ядро» или потенциально проблемные участки.
0 maxkoryukov 6 февраля 2010 в 16:26#↵↑
Нужно стремиться «покрыть» код тестами как можно полнее. Такое покрытие дает большой плюс при развитии уже внедренного продукта. Например, создали мы библиотеку, внедрили ее в свой проект, раздали в бесплатное пользование=). Все заработало, люди пользуются. Со временем оптимизируем ее и запускаем тесты на оптимизированной библиотеке. Если тесты прошли — значит новую версию с большой долей уверенности можно внедрять. Если нет — высока вероятность, что расти будет багтрак.
0 sindrom 5 февраля 2010 в 12:27#
Отличный топик! Я сам хотел написать про qunit, но вы меня опередили
0 1602 5 февраля 2010 в 22:37#↵↑
Всегда можно написать лучше
Читаю комменты и понимаю, что многие темы не раскрыты, например тестирование до разработки, либо тестирование в рабочем окружении.
+3 kmike 5 февраля 2010 в 12:32#
А мне больше jspec нравится (не путать с jsspec): github.com/visionmedia/jspec
Умеет все то же самое (а, вероятно, и больше, на qunit детально не смотрел: как там у него с загрузкой html-фикстур, иерархией тестов с общими подготовительными действиями?), + очень приятный синтаксис.
Если кого смутит, что там как будто тесты не на js нужно писать — это не так, там можно и на js писать, просто для сокращения количества писанины там препроцессор сделан.
Еще есть jsTestDriver ( code.google.com/p/js-test-driver/ ), штука позволяет запускать js-юнит-тесты (втч написанные на qunit) сразу в нескольких браузерах автоматом — из командной строки или по нажатии кнопки в плагине к эклипсу, и передавать результаты в браузер, в командную строку или эклипсовскому плагину. Причем запускать тесты можно даже на браузерах, которые расположены на другом компьютере. Это удобнее, чем в браузере смотреть, и еще более все автоматизируется. + Удивительно простая установка и настройка, все сразу работает. Только 1 минус — с mootools & prototype не работает ну никак, поэтому не использую)
0 1602 5 февраля 2010 в 22:43#↵↑
Спасибо за ссылки. Надо попробовать.
0 SeVit19 июля 2013 в 16:11#↵↑
jspec 404 теперь выдаёт (
0 wildmandnd 5 февраля 2010 в 14:22#
Также используем QUnit. У него есть странная, но похоже фундаментальная проблема — поскольку тесты запускаются в отдельном окружении, то часто глючат связи с плагинами. Чаще всего у нас проблемы с jQuery.Cookie — плагин не инициализируется в тестовом окружении. «Голые» же тесты — на ура, простенько и аккуратно.
+1 Iskin 5 февраля 2010 в 21:04#
При всём моём уважении к jQuery, JSpec мне нравится больше, хотя бы более красивой страницей вывода результатов.
0 STEVER25 сентября 2012 в 20:13#
Вот тут в конце поста дан альтернативный вариант запуска теста асинхронной цепочки вызовов.