Статьи

Как протестировать асинхронный код с помощью QUnit

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

Подобно синхронным функциям, асинхронные требуют любви и еще большего количества тестов. В этой статье я научу вас тестировать асинхронный код с помощью QUnit. Если вы не помните доступные методы утверждений или полностью пропустили мою статью, я советую прочитать « Начало работы с QUnit» . Материал, освещенный в нем, будет обязательным условием этой статьи.

Создание асинхронных тестов с помощью QUnit

Каждый нетривиальный проект, написанный на JavaScript, содержит асинхронные функции. Они используются для выполнения заданного действия через определенное время, для извлечения данных с сервера или события для отправки данных на сервер. QUnit предоставляет метод, называемый QUnit.asyncTest() , целью которого является тестирование асинхронного кода. Сигнатура метода:

 QUnit.asyncTest(name, testFunction) 

Значение параметров такое же, как QUnit.test() , но я QUnit.test() о них здесь для вашего удобства:

  • name : строка, которая помогает нам идентифицировать созданный тест.
  • testFunction : функция, содержащая утверждения, которые будет выполнять каркас. Каркас передает этой функции аргумент, который раскрывает все методы утверждения QUnit.

Тот факт, что этот метод принимает те же параметры, что и QUnit.test() может вводить в заблуждение. Вы можете подумать, что принцип тот же, и что все, что вам нужно сделать для проверки асинхронной функции, это заменить вызовы QUnit.test() на QUnit.asyncTest() и все готово. Не так быстро!

Чтобы выполнить свою работу, необходимо использовать QUnit.asyncTest() с двумя другими методами: QUnit.start() и QUnit.stop() . Давайте узнаем больше о них.

QUnit.start() и QUnit.stop()

Когда QUnit выполняет тест, созданный с использованием QUnit.asyncTest() , он автоматически останавливает тестирующий. Затем он будет ждать, пока функция, содержащая утверждения, не QUnit.start() . Цель QUnit.start() — запустить или возобновить работающий тест после его остановки. Этот метод принимает целое число в качестве единственного необязательного аргумента для объединения нескольких QUnit.start() в один .

Тест можно остановить с помощью метода QUnit.stop() . Это увеличивает количество QUnit.start() которые должен ждать тестирующий, прежде чем продолжить . Этот метод принимает целое число в качестве единственного необязательного аргумента, который указывает количество дополнительных вызовов QUnit.start() которые должна ждать инфраструктура. Его значение по умолчанию равно 1.

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

Собираем все вместе

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

Давайте начнем с простого примера, который использует одну из функций, разработанных в статье Начало работы с QUnit : max() . Эта функция принимает произвольное количество параметров и возвращает максимум. Код для функции приведен ниже:

 function max() { var max = -Infinity; for (var i = 0; i < arguments.length; i++) { if (arguments[i] > max) { max = arguments[i]; } } return max; } 

Теперь представьте, что эта функция обычно работает с очень большим набором параметров. Мы хотим, чтобы браузеры наших пользователей не блокировались до тех пор, пока не будет вычислен результат. По этой причине мы будем вызывать max() внутри обратного вызова, переданного window.setTimeout() со значением задержки 0 .

Код для асинхронного тестирования функции, который должен дать вам представление об использовании QUnit.start() , показан ниже:

 QUnit.asyncTest('max', function (assert) { expect(1); window.setTimeout(function() { assert.strictEqual(max(3, 1, 2), 3, 'All positive numbers'); QUnit.start(); }, 0); }); 

В приведенном выше коде я обернул вызов функции max() как обратный вызов window.setTimeout() . После того, как утверждение с использованием max() выполнено, мы вызываем метод QUnit.start() чтобы позволить testrunner возобновить его выполнение. Если бы мы избегали вызова этого метода, тестовый прогон застрял бы, и наш тест потерпел бы неудачу (на самом деле тест останавливается и больше ничего не делает, так что это не настоящий провал утверждения).

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

Полный код указан ниже:

 QUnit.asyncTest('max', function (assert) { expect(4); QUnit.stop(3); window.setTimeout(function() { assert.strictEqual(max(), -Infinity, 'No parameters'); QUnit.start(); }, 0); window.setTimeout(function() { assert.strictEqual(max(3, 1, 2), 3, 'All positive numbers'); QUnit.start(); }, 0); window.setTimeout(function() { assert.strictEqual(max(-10, 5, 3, 99), 99, 'Positive and negative numbers'); QUnit.start(); }, 0); window.setTimeout(function() { assert.strictEqual(max(-14, -22, -5), -5, 'All positive numbers'); QUnit.start(); }, 0); }); 

Внутри теста мы устанавливаем количество утверждений, которые мы ожидаем выполнить, как мы обсуждали в Приступая к работе с QUnit . Затем функция вызывает метод QUnit.stop() . Это необходимо, потому что внутри теста мы выполняем четыре асинхронных вызова. Когда мы используем QUnit.asyncTest() , фреймворк ожидает только одного вызова QUnit.start() . Если мы пропустим вызов QUnit.stop() указав три дополнительных вызова QUnit.start() , проверка не будет выполнена, поскольку ожидаемое число подтверждений отличается от числа выполненных утверждений.

Демонстрационная версия кода, в том числе вызов метода wait expect() , показана ниже и доступна в виде JSBin .

В этом разделе мы видели примеры асинхронного кода, который не выполняет операции Ajax. Однако вы часто хотите загружать данные с сервера или отправлять их на сервер. Когда это происходит, лучше не полагаться на фактические данные или результаты, возвращаемые сервером, потому что он может содержать ошибки (вы знаете, в программном обеспечении нет ничего идеального). Чтобы избежать этой проблемы, вы должны высмеивать запросы Ajax. Для этого вы можете использовать jQuery Mockjax , Sinon.js или любую другую библиотеку, которая соответствует вашим потребностям.

Вывод

В этом уроке вы узнали, как создавать тесты для ваших асинхронных функций. Сначала мы обсудили, как объявить тест с асинхронным кодом, используя метод QUnit.asyncTest() . Затем вы узнали о существовании двух других методов, QUnit.start() и QUnit.stop() , которые следует использовать при создании теста с QUnit.asyncTest() . Наконец, мы применили полученные знания к действию, разработав два теста, чтобы показать, как эти методы работают вместе.

Благодаря темам, которые рассматриваются в этом руководстве, у вас есть все возможности для тестирования любого кода, который вы можете написать с помощью JavaScript. Мне не терпится узнать ваше мнение об этой платформе и подумаете ли вы о ее использовании в своих проектах.