Pull to refresh

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).
Спасибо за внимание.
Tags:javascripttddtest driven developmentqunittestswarmunit testing
Hubs: JavaScript
Rating +65
Views 61k Add to bookmarks 354
Comments
Comments 23

Popular right now

Javascript разработчик
from 130,000 to 180,000 ₽ArtezioНижний Новгород
Javascript разработчик
from 160,000 to 220,000 ₽ArtezioМосква
Javascript разработчик
from 2,800 to 3,300 $ArtezioМогилев
Javascript разработчик
from 2,800 to 3,300 $ArtezioМинск
Javascript разработчик
from 2,800 to 3,300 $ArtezioВитебск