Средства модульного тестирования JavaScript

Применение QUnit, YUI Test и JSTestDriver

Некоторые разработчики жалуются на то, что JavaScript сложно тестировать. Однако, с учетом возрастающего внимания к клиентской стороне веб-приложений, модульное тестирование JavaScript приобретает все большую важность. Теперь у вас появились средства, позволяющие убедиться в работоспособности вашего кода. В этой статье вы узнаете о некоторых наиболее популярных инструментах для тестирования JavaScript, таких как QUnit, YUI Test и JSTestDriver, и познакомитесь на примерах с простыми сценариями тестирования.

Себастьяно Армели-Баттана, независимый разработчик программного обеспечения, Независимый разработчик

Sebastiono Armeli Battana photoСебастьяно Армели-Баттана (Sebastiano Armeli-Battana) – разработчик программного обеспечения, специализирующийся на разработке JavaScript и Java, страстный поклонник Web-технологий. Работает консультантом в компании SMS Management & Technology, внедряя Java-технологии, а также независимым Web-разработчиком. Является автором подключаемого jQuery-модуля JAIL. Вы можете посетить Web-сайт Себастьяно по адресу http://www.sebastianoarmelibattana.com.



06.08.2012

Введение

Суть модульного тестирования состоит в проверке того, работает ли код блока или модуля так, как задумано или ожидается. Некоторые разработчики, которые скорее предпочтут создавать новые модули, считают написание сценариев тестирования пустой тратой времени. Но при работе с большими приложениями модульное тестирование позволяет реально экономить время, помогая отслеживать проблемы и без риска обновлять код.

Часто используемые сокращения

  • DOM: объектная модель документов
  • HTML: язык гипертекстовой разметки
  • JSTD: JSTestDriver
  • YUI: Интерфейс пользователя Yahoo!

Ранее модульное тестирование применялось только в языках, используемых на стороне сервера. Но возрастающая сложность подсистем доступа привела к росту потребности в написании сценариев для тестирования кода JavaScript. При этом, если вы нечасто занимаетесь написанием сценариев для тестирования на клиентской стороне, кривая обучения может оказаться достаточно крутой. Тестирование интерфейса пользователя может потребовать пересмотра некоторых ваших убеждений. (Некоторые разработчики до сих пор не могут поверить, что JavaScript является серьезным языком программирования.)

В этой статье вы узнаете о применении QUnit, YUI Test и JSTestDriver для модульного тестирования JavaScript.

Загрузите исходный код для этой статьи.


Модульное тестирование JavaScript

Чтобы проиллюстрировать процесс тестирования JavaScript, в этом разделе анализируются сценарии тестирования базовых функций JavaScript. В листинге 1 показана функция, которую мы будет тестировать: она прибавляет число 3 к переданной переменной.

Листинг 1. Исходный код (example1/script.js)
function addThreeToNumber(el){
    return el + 3;
}

Листинг 2 содержит соответствующий сценарий тестирования в самовыполняющейся функции.

Листинг 2. Сценарий тестирования (example1/test.js)
(function testAddThreeToNumber (){
    var a = 5,
        valueExpected= 8;
    
    if (addThreeToNumber (a) === valueExpected) {
        console.log("Годен!");
    } else {
        console.log("Не годен!");
    }
}());

После передачи тестируемой функции числа 5 тест проверяет, равно ли возвращаемое значение 8. Если тест прошел успешно, на консоль современного браузера выводится сообщение Годен!; в противном случае появляется сообщение Не годен! Для запуска этого теста нужно:

  1. импортировать два файла сценария в страницу HTML, которая будет играть роль среды тестирования, как показано в листинге 3;
  2. открыть эту страницу в браузере.
Листинг 3. Страница HTML (example1/runner.html)
<!DOCTYPE html>
<html>
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8">
         <title>Example 1</title>
         <script type="text/javascript" src="js/script.js"></script>
          <script type="text/javascript" src="js/test.js"></script>
     </head>
     <body></body>
</html>

Вместо того чтобы использовать консоль браузера, можно распечатать результаты внутри страницы или внутри всплывающего окна, созданного методом alert().

Для проверки соответствия определенным условиям используются тестовые утверждения, составляющие основу сценариев тестирования. Например, в листинге 2 в роли тестового утверждения выступает выражение addThreeToNumber (a) === valueExpected.

Если у вас есть несколько сценариев тестирования с несколькими тестовыми утверждениями, то удобнее использовать интегрированную среду. В следующих разделах будут описаны некоторые наиболее популярные интегрированные среды для тестирования модулей JavaScript: QUnit, YUI Test и JSTestDriver.


Приступаем к работе с QUnit

QUnit, интегрированная среда для модульного тестирования, подобная JUnit (программирование на Java), используется группой jQuery для тестирования библиотеки jQuery. Для использования QUnit нужно:

  1. загрузить файлы qunit.css и qunit.js (см. Ресурсы);
  2. создать страницу HTML с соответствующими тегами и импортировать в нее файлы CSS и JavaScript, которые вы только что загрузили.

В листинге 4 показана стандартная HTML-страница для запуска QUnit.

Листинг 4. Исполняющая HTML-страница (qunit/runner.html)
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>QUnit Test Suite</title>
        <link rel="stylesheet" href="css/qunit.css" type="text/css" media="screen">
        <script type="text/javascript" src="js/lib/qunit.js"></script>
    </head>
    <body>
        <h1 id="qunit-header">QUnit Test Suite</h1>
        <h2 id="qunit-banner"></h2>
        <div id="qunit-testrunner-toolbar"></div>
        <h2 id="qunit-userAgent"></h2>
        <ol id="qunit-tests"></ol>
        <div id="qunit-fixture">test markup</div>
    </body>
</html>

Предположим, что у нас есть две функции, выполняющие преобразование температуры из градусов по Цельсию в градусы по Фаренгейту и обратно. Сценарий таких преобразований показан в листинге 5.

Листинг 5. Преобразования (qunit/js/script.js)
function convertFromCelsiusToFahrenheit(c){
    var f = c * (9/5) + 32;
    return f;
}

function convertFromFahrenheitToCelsius(f){
    var c = (f - 32) * (5/9);
    return c;
}

В листинге 6 показаны соответствующие сценарии тестирования.

Листинг 6. Сценарии тестирования (qunit/js/test.js)
module ("Преобразование температуры")

test("преобразование в F", function(){
    var actual1 = convertFromCelsiusToFahrenheit(20);
    equal(actual1, 68, ?Значение неверно?);
	
    var actual2 = convertFromCelsiusToFahrenheit(30);
    equal(actual2, 86, ?Значение неверно?);
})

test("преобразование в C", function(){
    var actual1 = convertFromFahrenheitToCelsius(68);
    equal(actual1, 20, ?Значение неверно?);

    var actual2 = convertFromFahrenheitToCelsius(86);
    equal(actual2, 30, ?Значение неверно?);
})

Сценарии тестирования в QUnit определяются методом test(). Логика содержится во втором аргументе, передаваемом в эту функцию. В листинге 6 использованы два сценария тестирования, названные преобразование в F и преобразование в C. Каждый тест содержит два тестовых утверждения, которые используют метод equal(). Функция equal() позволяет сравнить ожидаемое значение с фактическим значением, возвращаемым тестируемой функцией. Третий аргумент метода equal() представляет собой сообщение, которое выводится в случае неудачи.

Тесты можно оформить в виде модулей с помощью функции module(). В листинге 6 оба теста находятся в модуле Преобразование температуры.

Для запуска тестов:

  1. включите исходный код и тестовый файл в исполняющую HTML-страницу, как показано в листинге 7;
  2. откройте эту HTML-страницу в браузере.
Листинг 7. Включение script.js и test.js в исполняющую HTML-страницу
...
<script type="text/javascript" src="js/script.js"></script>
<script type="text/javascript" src="js/test.js"></script>
...

Рисунок 1 показывает, как QUnit отображает результаты в браузере Firefox.

Рисунок 1. Результат QUnit
A screen shot showing that 4 out of 4 tests were successful.

Тестовые утверждения в листинге 6 используют метод equal(), но это не единственная возможность, предлагаемая QUnit. Другие доступные в QUnit тестовые утверждения включают ok() и strictEqual(). Применение этих методов показано в листинге 8.

Листинг 8. Другие тестовые утверждения
module ("Другие тестовые утверждения");
test("тестовые утверждения", function(){
    ok(true);
    ok(3);
    strictEqual("c", "c");
    equal (3, "3");
});

Функция ok() проверяет истинность первого параметра; strictEqual() проверяет, что первый параметр строго равен второму. За кадром strictEqual() использует оператор ===, а equal() использует оператор ==.

Кроме того, QUnit предоставляет полезную информацию в случае неудачного выполнения теста. Замените код листинга 8 кодом листинга 9, чтобы последнее тестовое утверждение сработало неудачно.

Листинг 9. Ошибка последнего тестового утверждения
module ("Другое тестовое утверждение");
test("тестовые утверждения", function(){
    ok(true);
    ok(3);
    strictEqual("c", "c");
    strictEqual (3, "3");
});

На рисунке 2 показано, какой результат вернет QUnit в ответ на код в листинге 9.

Рисунок 2. Результат QUnit — неудачный последний тест
Screen shot showing that 7 out of 8 tests passed and 1 failed.

Результат содержит подробный отчет, позволяющий понять, в чем именно состоит отличие ожидаемого значения от реального в последнем тестовом утверждении.

Другая важная функция QUnit позволяет выполнять команды до или после выполнения всех тестов внутри модуля. Функция module() принимает в качестве второго параметра возвращаемые значения функций setup() и teardown(). Обновите листинг 6 добавив функцию setup(), как показано в листинге 10.

Листинг 10. setup() (qunit/js/test-setup.js)
module ("Преобразование температуры", {
    setup : function() {
        this.celsius1 = 20;
        this.celsius2 = 30;
		
        this.fahrenheit1 = 68;
        this.fahrenheit2 = 86;
    }
});
test("преобразование в F", function(){
    var actual1 = convertFromCelsiusToFahrenheit(this.celsius1);
    equal(actual1, this.fahrenheit1);
	
    var actual2 = convertFromCelsiusToFahrenheit(this.celsius2);
    equal(actual2, this.fahrenheit2);
});
test("преобразование в C", function(){
    var actual1 = convertFromFahrenheitToCelsius(this.fahrenheit1);
    equal(actual1, this.celsius1);
	
    var actual2 = convertFromFahrenheitToCelsius(this.fahrenheit2);
    equal(actual2, this.celsius2);
});

В этом примере значения, используемые в тестовых утверждениях, перенесены в раздел setup, чтобы избежать использования этих значений в логике тестов.

Кроме того, QUnit поддерживает асинхронное тестирование с помощью функции asyncTest(), которая очень полезна, если вы имеете дело с асинхронным JavaScript и XML (Ajax). В этом контексте функция expect() позволяет проверить число тестовых утверждений в тесте.


YUI Test: независимый модуль для модульного тестирования

YUI Test является компонентом библиотеки YUI (Yahoo!) и представляет собой интегрированную среду для всестороннего и полного модульного тестирования. Чтобы начать работу с YUI Test, нужно:

  1. Импортировать зерно YUI в исполняющую HTML-страницу:
    <script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>

    Как видно из кода, этот пример использует YUI Test версии 3.
  2. Создать в файле тестового сценария экземпляр функции YUI и загрузить необходимые модули test и console, как показано в листинге 11.
Листинг 11. Загрузка YUI-модулей test и console
YUI().use("test", "console", function (Y) {
     // Сюда вставляются сценарии тестирования
});

Модуль test необходим для тестирования, тогда как модуль console не обязателен, но в нашем примере он используется для распечатки результатов. Сценарии тестирования располагаются внутри обратного вызова, причем в качестве аргумента используется глобальный экземпляр Y.

YUI Test использует конструктор Y.Test.Case() для создания экземпляра нового сценария тестирования и конструктор Y.Test.Suite() для создания экземпляра набора тестов. Набор тестов, подобно JUnit, содержит несколько сценариев тестирования. Добавлять тесты в набор можно с помощью метода add().

Давайте еще раз протестируем исходный код в листинге 5 с помощью YUI Test. В листинге 12 показано, как создать набор тестов и сценарий тестирования.

Листинг 12. Набор тестов и сценарий тестирования
YUI().use("test", "console", function (Y) {
	
     var suite = new Y.Test.Suite("Набор для преобразования температуры");

     //добавить сценарий тестирования
     suite.add(new Y.Test.Case({
         name: "Преобразование температуры"
     )); 
});

Код в листинге 12 создает набор с именем Набор для преобразования температуры и сценарий тестирования с именем Преобразование температуры. Теперь вы можете написать методы тестирования внутри объектного литерала (object literal), передаваемого в качестве аргумента конструктору Y.Test.Case, как показано в листинге 13.

Листинг 13. Сценарии тестирования с методами тестирования
suite.add(new Y.Test.Case({
    name: "Преобразование температуры",

    setUp : function () {
        this.celsius1 = 20;
        this.celsius2 = 30;
		
        this.fahrenheit1 = 68;
        this.fahrenheit2 = 86;
    },

    testConversionCtoF: function () {
        Y.Assert.areEqual(this.fahrenheit1,         
convertFromCelsiusToFahrenheit(this.celsius1));
        
        Y.Assert.areEqual(this.fahrenheit2, 
convertFromCelsiusToFahrenheit(this.celsius2));
    },
		
    testConversionFtoC: function () {
        Y.Assert.areEqual(this.celsius1,
convertFromFahrenheitToCelsius(this.fahrenheit1));
			
        Y.Assert.areEqual(this.celsius2, 
convertFromFahrenheitToCelsius(this.fahrenheit2));
    }
}));

Вероятно, вы заметили, что в листинге 13:

  • Доступен метод setUp(). YUI Test предоставляет методы setUp() и tearDown() на уровне сценария тестирования и набора тестов.
  • Имена методов тестирования начинаются со слова test, а сами методы содержат тестовые утверждения
  • В примере использовано тестовое утверждение Y.Assert.areEqual(), аналогичное функции equal() в QUnit.

    YUI Test предоставляет широкий диапазон методов контроля, например:

    • Y.Assert.areSame(), эквивалентный функции strictEqual() в QUnit.
    • Тестовые утверждения для типов данных (Y.Assert.isArray(), Y.Assert.isBoolean(), Y.Assert.isNumber(), и т.п.).
    • Тестовые утверждения для специальных значений (Y.Assert.isFalse(), Y.Assert.isNaN(), Y.Assert.isNull(), и т.п.).

Для запуска теста в YUI используйте объект Y.Test.Runner. Добавьте в этот объект наборы тестов или сценарии тестирования и затем вызовите метод run() для запуска тестов. В листинге 14 показано, как запустить тесты, созданные в листинге 13.

Листинг 14. Запуск тестов YUI
Y.Test.Runner.add(suite);
Y.Test.Runner.run();

По умолчанию результаты распечатываются в консоли браузера (если ваш браузер поддерживает консоль), но лучше распечатывать результаты с помощью консольного компонента Yahoo!. Чтобы воспользоваться консольным компонентом Yahoo!, вам нужно взять конструктор Y.Console и привязать консоль к элементу DOM исполняющей HTML-страницы, как показано в листинге 15.

Листинг 15. Консоль Yahoo!
var console = new Y.Console({
    verbose: true,
    newestOnTop: false,
    width: "600px"
});

console.render('#testLogger');

В листинге 15 показано, как настроить консоль с несколькими параметрами. Консоль выполняется внутри элемента DOM, причем id равен testLogger.

Исполняющую HTML-страницу необходимо обновить. Добавьте используемый консолью элемент DOM, как показано в листинге 16.

Листинг 16. Обновление исполняющей HTML-страницы для поддержки консоли Yahoo!
<body class="yui3-skin-sam">
     <div id="testLogger"></div> 
</body>

В этом примере определяется класс для <body> с именем yui3-skin-sam. Этот класс отвечает за определение оболочки консоли.

На рисунке 3 показана консоль после запуска тестов.

Рисунок 3. Результат YUI Test
Screen capture of the log console showing the results of each test.

Простое тестирование с помощью JSTestDriver

Мощный инструмент JSTestDriver (JSTD) позволяет запускать JavaScript из командной строки во многих браузерах. В комплект поставки JSTD входит файл JAR, позволяющий запустить сервер, захватить один или несколько браузеров и запустить тесты в этих браузерах. При этом вам не понадобится исполняющая HTML-страница, как в двух других описанных выше системах, но потребуется конфигурационный файл. Такой конфигурационный файл показан в листинге 17.

Листинг 17. Конфигурационный файл (jsTestDriver.conf)
server: http://localhost:4224
load:
  - js/src/*.js
test:
  - js/test/*.js

Этот конфигурационный файл написан на языке YAML, который очень удобен для создания конфигурационных файлов. Он содержит информацию о запускаемом сервере и о местоположении исходного кода и тестовых файлов.

Для выполнения тестов с помощью JSTD:

  1. Запустите тестовый сервер. Из командной строки перейдите в папку, в которой сохранен файл jsTestDriver.jar, и подайте следующую команду:
    java -jar JsTestDriver-1.3.3d.jar -port 4224

    Порт, указанный в листинге 17, должен совпадать с портом, указанным в конфигурационном файле. По умолчанию JSTD ищет файл jsTestDriver.conf в той же директории, где находится файл JAR.

  2. 2. Зарегистрируйте на сервере один или несколько браузеров, скопировав и вставив в тестируемый браузер адрес http://localhost:4224/capture.

Проверьте тот же исходный код, который вы использовали в предыдущих примерах (листинг 5), но на это раз используйте синтаксис JSTD. В листинге 18 показано, как преобразовать сценарии тестирования из листинга 10 для QUnit и листинга 14 для YUI Test..

Листинг 18. Тесты JSTD
TestCase("Преобразование температуры", {
    setUp : function () {
        this.celsius1 = 20;
        this.celsius2 = 30;
	
        this.fahrenheit1 = 68;
        this.fahrenheit2 = 86;
    },

    testConversionCtoF: function () {
        assertSame(this.fahrenheit1, convertFromCelsiusToFahrenheit(this.celsius1));
        assertSame(this.fahrenheit2, convertFromCelsiusToFahrenheit(this.celsius2));
    },
	
    testConversionFtoC: function () {
        assertSame(this.celsius1, convertFromFahrenheitToCelsius(this.fahrenheit1));
        assertSame(this.celsius2, convertFromFahrenheitToCelsius(this.fahrenheit2));
    }
});

Код в листинге 18 почти не отличается от версии YUI. Для определения сценария тестирования JSTD использует функцию TestCase(). Методы тестирования можно определить с помощью внутристрочного объявления, как в листинге 18, или же расширить прототип экземпляра TestCase. Методы SetUp() и tearDown() доступны для каждого сценария тестирования.

Для запуска тестов просто подайте следующую команду:

java -jar JsTestDriver-1.3.3d.jar --tests all

На рисунке 4 показан текст, который выводится на терминал.

Рисунок 4. Результаты тестов JSTD
Command line results showing which tests passed and which failed.

Тесты успешно выполняются во всех захваченных ранее браузерах (Chrome 15, Safari 5, и Firefox 7).

Кроме того, JSTD отлично встраивается в вашу любимую интегрированную систему и становится ее частью. Он поддерживает интеграцию в такие интегрированные среды разработки (IDE), как Eclipse (подключаемый модуль) или TextMate (пакет).


Заключение

С учетом возрастающего внимания к клиентской стороне веб-приложений тестирование модулей JavaScript приобретает все большую важность. Существует несколько систем, которые могут помочь в решении этой задачи; в этой статье рассматриваются три наиболее популярные системы: QUnit, YUI Test и JSTestDriver.

  • Начинать работу лучше с QUnit, который очень прост в применении.
  • YUI Test предлагает полный набор инструментов для тех, кто знаком с библиотекой YUI.
  • JSTestDriver превосходно подходит для запуска тестов в нескольких браузерах.

Загрузка

ОписаниеИмяРазмер
Исходный код для статьиIBM_UnitTestingJS.zip54 KБ

Ресурсы

Научиться

Получить продукты и технологии

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, SOA и web-сервисы
ArticleID=829441
ArticleTitle=Средства модульного тестирования JavaScript
publish-date=08062012