31.07.2023

Тест на знание js. Как протестировать код Javascript с помощью QUnit. QUnit – классика жанра от создателей jQuery


Javascript - очень популярный язык для клиентской веб-разработки. Язык JavaScript является динамическим языком и базируется на прототипировании. Не смотря на название, он не относится к языку Java, хотя и использует схожий C-подобный синтаксис, схожие конвенции именования.

Последнее время Javascript начал завоевывать все большую популярность. Он лежит в основе такой современной технологии как AJAX. Знание javascript может пригодится и для программирования на стороне сервера для гибкого конфигурирования систем.

Целевая аудитория теста по JavaScript

Данный тест рекомендуется к сдаче специалистам, желающим проверить свои базовые знания в области JavaScript. Также тест может применяться для закрепления знаний разработчиками непосредственно после ознакомления с языком JavaScript.

В высших учебных заведениях данный тест будет интересен студентам технических специальностей по направлениям "Инженерия программного обеспечения" или "Программное обеспечение Интернет".

Предварительные требования к тесту javascript

Перед тем, как пройти данный тест, необходимо получить хотя бы общее представление о языке Javascript.

Тест ориентирован в первую очередь на специалистов, недавно изучивших JavaScript. Поэтому данный тест не покрывает такие сложные темы как ООП в JavaScript или специализированное JavaScript API.

Структура теста по JavaScript

Вопросы теста покрывают следующие темы:

  • основные языковые конструкции JavaScript (объявление переменных, функций и т.д.);
  • операторы (ветвление, циклы);
  • работу со строками в JavaScript;
  • работу с массивами в JavaScript;
  • связку "JavaScript - HTML" (теги, используемые для интеграции)
  • другие понятия, которые не вошли в обозначенные выше темы.
Дальнейшее развитие теста по JavaScript

Следующим шагом в развитии теста по Javascript будет составление вопросов по существующим темам теста. Расширение списка вопросов увеличит интерес повторного прохождения теста как в целях проверки знаний, так и в целях обучения.

Теперь на сайте доступно тестирование на знание следующих тем: HTML , CSS , JavaScript , PHP , SQL .

Каждый тест состоит из 10-ти вопросов по определённой теме. Я старался в каждом вопросе затрагивать самые разнообразные области применения конкретного языка, чтобы максимально тщательно проверить Ваш уровень знаний.

Безусловно, все тесты бесплатные и пройти их может любой желающий.

Порядок прохождения теста:

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

    Доступные на данный момент тесты
  • HTML
    • Всего тест прошло: 75424 человека
    • Средний балл: 2.83 из 5 баллов.

    Тест на знание основ HTML . От Вас потребуется знание основных HTML-тегов , а также грамотное их использование. Так же необходимо понимание особенностей стандарта XHTML 1.1 .

  • CSS
    • Всего тест прошло: 32828 человек
    • Средний балл: 3.37 из 5 баллов.

    Тест проверяет знания по основам CSS . Для успешного прохождения теста Вы должны знать основные виды селекторов (их синтаксис), знать основные свойства и их возможные значения, а также знать назначение самых популярных псевдоэлементов.

  • JavaScript
    • Всего тест прошло: 24845 человек
    • Средний балл: 3.31 из 5 баллов.

    Данный тест проверяет Ваши знания по языку JavaScript. Вопросы из теста затрагивают разные области применения данного языка. Очень много вопросов имеется на понимание "мелких" нюансов. В остальном же от Вас требуется знание базовых вещей: работа с переменными, основные функции JavaScript, приоритеты операций и прочее.

  • PHP
    • Всего тест прошло: 33239 человек
    • Средний балл: 3.03 из 5 баллов.

    Данный тест проверяет Ваши знания по языку PHP. От Вас требуется знание основных конструкций PHP, работы с переменными, сессий, реализации редиректа и прочих стандартных вещей.
    Убедительная просьба: В тесте содержится много вопросов по типу: "Что выведет скрипт?". Большая просьба, не надо копировать его и проверять. Будьте честны перед самими собой.

  • SQL
    • Всего тест прошло: 18014 человек
    • Средний балл: 3.28 из 5 баллов.

    Данный тест проверяет Ваши знания по языку запросов SQL. Вопросы затрагивают только самые базовые знания этого языка, без какого-либо углубления. От Вас потребуется знание самых основных SQL-запросов, а также грамотное их использование.

  • На примере простого приложения-калькулятора на Node.js. Тестировать будем с помощью фреймворка Mocha.

    Что должно уметь наше приложение:

    • Складывать, вычитать, делить и умножать любые два числа;
    • Показывать предупреждение и завершать работу, если было введено что-то отличное от числа;
    • Также должен быть интерфейс командной строки, чтобы конечный пользователь мог воспользоваться приложением.

    Что нам потребуется:

    • Node.js и npm;
    • Знание JavaScript: синтаксис и структура кода , типы данных , математические операции и условные выражения .

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

    Настраиваем среду

    Так как мы используем Node.js, нужно создать локальное окружение для файлов и зависимостей.

    Создайте новую папку calc . В командной строке перейдите в эту директорию и создайте новый проект командой npm init , которая создаст новый файл package.json для нашей программы.

    Вам предложат ввести имя пакета, версию, описание и прочую информацию о пакете. Вы можете ввести имя calc.js и дальше жать Enter для присвоения значений по умолчанию. Когда вы дойдёте до test command , введите mocha - это фреймворк для тестирования, который мы будем использовать:

    test command: mocha

    После ввода всей информации скрипт создаст файл package.json , который выглядит примерно так:

    { "name": "calc.js", "version": "1.0.0", "description": "Простой калькулятор на Node.js", "main": "index.js", "scripts": { "test": "mocha" }, "author": "", "license": "ISC" }

    Последний шаг на данном этапе - установка Mocha. Введите следующую команду для установки:

    Npm install --save-dev mocha

    После применения этой команды появится папка node_modules , файл package-lock.json , а в файле package.json появятся следующие строки:

    "devDependencies": { "mocha": "^4.0.1" }

    Создайте файл test.js . Мы воспользуемся встроенным в Node.js модулем assert , чтобы проверить верность равенства true и true . Так как оно верно, тест должен пройти успешно:

    Const assert = require("assert"); it("должно возвращать true", () => { assert.equal(true, true); });

    Теперь запустите тест из командной строки:

    $ npm test > mocha ✓ должно возвращать true 1 passing (8ms)

    Тест прошёл как и ожидалось, поэтому с настройкой среды покончено. Удалите из test.js всё, кроме строки const assert = require("assert"); .

    Мы будем использовать файл test.js на протяжении всего процесса создания приложения. Создайте ещё два файла: operations.js для арифметических и валидационных функций и calc.js для самого приложения. Мы используем так много файлов, чтобы они не становились слишком длинными и сложными. Вот наш текущий список файлов:

    • calc.js ;
    • node_modules ;
    • operations.js ;
    • package-lock.json ;
    • package.json ;
    • test.js ;

    Давайте добавим первый настоящий тест для нашего приложения.

    Добавляем математические операции

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

    Начнём со сложения. Мы напишем тест, в котором однозначно получится ожидаемая сумма двух чисел. В коде ниже мы проверяем, равняется ли сумма 1 и 3 с помощью функции add() 4:

    Const assert = require("assert"); it("правильно находит сумму 1 и 3", () => { assert.equal(add(1, 3), 4); });

    После запуска теста с помощью команды npm test мы видим следующее:

    > mocha 0 passing (9ms) 1 failing 1) правильно находит сумму 1 и 3: ReferenceError: add is not defined at Context.it (test.js:5:16) npm ERR! Test failed. See above for more details.

    Тест провалился с сообщением ReferenceError: add is not defined . Мы тестируем функцию add() , которой ещё нет, поэтому такой результат вполне ожидаем.

    Создадим функцию add() в файле operations.js :

    Const add = (x, y) => (+x) + (+y);

    Эта функция принимает два аргумента x и y и возвращает их сумму. Вы могли заметить, что мы пишем (+x) + (+y) , а не x + y . Мы используем унарный оператор для приведения аргумента к числу, на случай, если ввод будет строкой.

    Примечание Здесь используется добавленная в ES6 стрелочная функция и неявный возврат.

    Так как мы используем Node.js и разбиваем код на множество файлов, нужно воспользоваться module.exports , чтобы экспортировать код:

    Const add = (x, y) => (+x) + (+y); module.exports = { add }

    В начале файла test.js мы импортируем код из operations.js с помощью require() . Так как мы используем функцию через переменную operations , нужно поменять add() на operations.add() :

    Const operations = require("./operations.js"); const assert = require("assert"); it("правильно находит сумму 1 и 3", () => { assert.equal(operations.add(1, 3), 4); });

    Запускаем тест:

    $ npm test > mocha ✓ правильно находит сумму 1 и 3 1 passing (8ms)

    Теперь у нас есть работающая функция, и тесты проходят успешно. Так как функции других операций работают схожим образом, добавить тесты для subtract() , multiply() и divide() не составит труда:

    It("правильно находит сумму 1 и 3", () => { assert.equal(operations.add(1, 3), 4); }); it("правильно находит сумму -1 и -1", () => { assert.equal(operations.add(-1, -1), -2); }); it("правильно находит разность 33 и 3", () => { assert.equal(operations.subtract(33, 3), 30); }); it("правильно находит произведение 12 и 12", () => { assert.equal(operations.multiply(12, 12), 144); }); it("правильно находит частное 10 и 2", () => { assert.equal(operations.divide(10, 2), 5); });

    Теперь создадим и экспортируем все функции в test.js :

    Const add = (x, y) => (+x) + (+y); const subtract = (x, y) => (+x) - (+y); const multiply = (x, y) => (+x) * (+y); const divide = (x, y) => (+x) / (+y); module.exports = { add, subtract, multiply, divide, }

    И запустим новые тесты:

    $ npm test > mocha ✓ правильно находит сумму 1 и 3 ✓ правильно находит сумму -1 и -1 ✓ правильно находит разность 33 и 3 ✓ правильно находит произведение 12 и 12 ✓ правильно находит частное 10 и 2 5 passing (8ms)

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

    Добавляем валидацию

    На данный момент, когда пользователь вводит число и выбирает нужную операцию, всё работает нормально. Однако что случится, если попытаться найти сумму числа и строки? Приложение попытается выполнить операцию, но из-за того, что оно ожидает числа, оно вернёт NaN .

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

    Сначала нужно написать функцию, которая будет проверять, является ли ввод числом или нет. Приложение должно работать только с числами, поэтому мы будем обрабатывать три ситуации:

  • Оба ввода - числа.
  • Один ввод - число, а другой - строка.
  • Оба ввода - строки.
  • it("сообщает об ошибке при использовании строки вместо числа", () => { assert.equal(operations.validateNumbers("sammy", 5), false); }); it("сообщает об ошибке при использовании двух строк вместо чисел", () => { assert.equal(operations.validateNumbers("sammy", "sammy"), false); }); it("успех при использовании двух чисел", () => { assert.equal(operations.validateNumbers(5, 5), true); });

    Функция validateNumbers() будет проверять оба параметра. Функция isNaN() проверяет, не является ли параметр числом, и если нет, то возвращает false . В противном случае она возвращает true , что означает успешную валидацию.

    Const validateNumbers = (x, y) => { if (isNaN(x) && isNaN(y)) { return false; } return true; }

    Не забудьте добавить validateNumbers в module.exports в конце файла. Теперь можно запускать новые тесты:

    $ npm test 1) сообщает об ошибке при использовании строки вместо числа ✓ сообщает об ошибке при использовании двух строк вместо чисел ✓ успех при использовании двух чисел 7 passing (12ms) 1 failing 1) сообщает об ошибке при использовании строки вместо числа: AssertionError : true == false + expected - actual -true +false

    Два теста прошли, но один провалился. Проверка на ввод двух чисел прошла успешно, так же как и проверка на ввод двух строк. Чего нельзя сказать о проверке на ввод строки и числа.

    Если взглянуть на нашу функцию ещё раз, то можно заметить, что оба параметра должны быть NaN , чтобы функция вернула false . Если мы хотим добиться того же эффекта, когда хотя бы один из параметров равен NaN , нужно заменить && на || :

    Const validateNumbers = (x, y) => { if (isNaN(x) || isNaN(y)) { return false; } return true; }

    Если после этих изменений снова запустить npm test , то все тесты пройдут успешно:

    ✓ сообщает об ошибке при использовании строки вместо числа ✓ сообщает об ошибке при использовании двух строк вместо чисел ✓ успех при использовании двух чисел 8 passing (9ms)

    Мы протестировали всю функциональность нашего приложения. Функции успешно выполняют математические операции и проверяют ввод. Финальный этап - создание пользовательского интерфейса.

    Создаём интерфейс

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

    На данный момент файл calc.js должен быть пуст. Здесь и будет храниться наше приложение. Сначала нужно импортировать функции из operations.js :

    Const operations = require("./operations.js");

    Сам интерфейс будет использовать встроенный в Node.js CLI-модуль Readline :

    Const readline = require("readline");

    После импортирования всего, что нужно, можно приступить к созданию приложения. Для создания интерфейса мы будем использовать readline , доступный через переменную rl:

    Const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

    Первое, что пользователь должен видеть после запуска программы, - приветственное сообщение и инструкции по использованию. Для этого мы воспользуемся console.log() :

    Console.log(` Calc.js Вы открыли калькулятор на Node.js! Версия: 1.0.0. Использование: пользователь должен ввести два числа, а затем выбрать, что с ними сделать. `);

    Прежде чем мы займёмся самими функциями калькулятора, давайте проверим, что console.log() работает как надо. Мы сделаем так, чтобы программа выводила сообщение и завершала работу. Для этого добавьте в конце вызов метода rl.close() .

    Чтобы запустить приложение, введите node и имя файла:

    $ node calc.js Calc.js Вы открыли калькулятор на Node.js! Версия: 1.0.0. Использование: пользователь должен ввести два числа, а затем выбрать, что с ними сделать.

    Программа выводит приветственное сообщение и завершает свою работу. Теперь нужно добавить пользовательский ввод. От пользователя требуется следующее: выбрать два числа и одну операцию. Каждый ввод будет запрашиваться методом rl.question() :

    Rl.question("Введите первое число: ", (x) => { rl.question("Введите второе число: ", (y) => { rl.question(` Выберите одну из следующих операций: Сложение (+) Вычитание (-) Умножение (*) Деление (/) Ваш выбор: `, (choice) => { // здесь ещё появится код rl.close(); }); }); });

    Переменной x присваивается первое число, y - второе, а choice - выбранная операция. Теперь наша программа запрашивает ввод, но ничего не делает с полученными данными.

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

    If (!operations.validateNumbers(x, y)) { console.log("Можно вводить только числа! Пожалуйста, перезапустите программу."); }

    Если всё введено верно, то теперь нужно запустить соответствующий операции метод, созданный ранее. Для обработки четырёх возможных вариантов выбора мы воспользуемся выражением switch и выведем результат операции. Если была выбрана несуществующая операция, будет выполнен блок default , сообщающий пользователю о необходимости повторить попытку:

    If (!operations.validateNumbers(x, y)) { console.log("Можно вводить только числа! Пожалуйста, перезапустите программу."); } else { switch (choice) { case "1": console.log(`Сумма ${x} и ${y} равна ${operations.add(x, y)}.`); break; case "2": console.log(`Разность ${x} и ${y} равна ${operations.subtract(x, y)}.`); break; case "3": console.log(`Произведение ${x} и ${y} равно ${operations.multiply(x, y)}.`); break; case "4": console.log(`Частное ${x} и ${y} равно ${operations.divide(x, y)}.`); break; default: console.log("Пожалуйста, перезапустите программу и выберите число от 1 до 4."); break; } }

    Примечание Здесь в функциях console.log() используются шаблонные строки , допускающие использование выражений.

    /** * Простой калькулятор на Node.js, который использует calculator app that uses * встроенный интерфейс командной строки Readline. */ const operations = require("./operations.js"); const readline = require("readline"); // Используем readline для создания интерфейса const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log(` Calc.js Вы открыли калькулятор на Node.js! Версия: 1.0.0. Использование: пользователь должен ввести два числа, а затем выбрать, что с ними сделать. `); rl.question("Введите первое число: ", (x) => { rl.question("Введите второе число: ", (y) => { rl.question(` Выберите одну из следующих операций: Сложение (+) Вычитание (-) Умножение (*) Деление (/) Ваш выбор: `, (choice) => { if (!operations.validateNumbers(x, y)) { console.log("Можно вводить только числа! Пожалуйста, перезапустите программу."); } else { switch (choice) { case "1": console.log(`Сумма ${x} и ${y} равна ${operations.add(x, y)}.`); break; case "2": console.log(`Разность ${x} и ${y} равна ${operations.subtract(x, y)}.`); break; case "3": console.log(`Произведение ${x} и ${y} равно ${operations.multiply(x, y)}.`); break; case "4": console.log(`Частное ${x} и ${y} равно ${operations.divide(x, y)}.`); break; default: console.log("Пожалуйста, перезапустите программу и выберите число от 1 до 4."); break; } } rl.close(); }); }); });

    Теперь наше приложение готово. Проверим его работу напоследок. Введём 999 и 1 и выберем операцию вычитания:

    $ node calc.js Введите первое число: 999 Введите второе число: 1 Ваш выбор: 2 Разность 999 и 1 равна 998.

    Программа успешно завершила свою работу, выведя правильный результат. Поздравляем, вы написали простой калькулятор с помощью Node.js и изучили основы TDD-разработки.

    И является официальным инструментом для тестирования jQuery. Но QUnit отлично подходит для тестирования любого кода JavaScript и даже способна тестировать серверную часть JavaScript с помощью механизмов наподобие Rhino или V8.

    Если вы не знакомы с идеей "модульного тестирования", не огорчайтесь - в ней нет ничего сложного для понимания:

    "Модульное тестирование или юнит-тестирование (англ. unit testing ) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы. Идея состоит в том, чтобы писать тесты для каждой нетривиальной функции или метода. Это позволяет достаточно быстро проверить, не привело ли очередное изменение кода к регрессии , то есть к появлению ошибок в уже оттестированных местах программы, а также облегчает обнаружение и устранение таких ошибок."

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

    Зачем следует тестировать свой код

    Если вы никогда не писали модульных тестов раньше, то, вероятно, просто размещали свой код сразу на веб сервере, запускали его, следили за проявлением ошибок и пытались устранить их по мере обнаружения. Такой метод работы рождает много проблем.

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

    Во-вторых, все, что делается для такого тестирования, не может быть использовано повторно. При таком методе очень сложно найти регрессии. Что такое регрессии? Представьте, что вы написали некий код и протестировали его, исправили все ошибки, которые нашли, и поместили код на сайте. Затем пользователь прислал отзыв о новых ошибках и запрос на новые функции. Вы возвращаетесь к коду, исправляете ошибки и добавляете новые функции. При этом может возникнуть ситуация, когда старые ошибки проявляются снова, что называется "регрессией". Вам снова приходится все проверять. И есть шанс, что вы не найдете свои старые ошибки. В любом случае пройдет время, прежде чем вы догадаетесь, что проблема вызвана "регрессией". При использовании модульного тестирования вы пишите тест. Как только код модифицируется, вы снова фильтруете его через тест. Eсли регрессия проявляется, то какие-нибудь тесты не пройдут, и вы легко определите, какая часть кода содержит ошибку. Так как вы знаете, что изменили, то ошибку будет легко исправить.

    Другим преимуществом модульного тестирования (особенно для веб разработок) является то, что легко протестировать кросс-браузерную совместимость. Нужно просто запустить тесты в различных браузерах. Если обнаружатся проблемы в браузере, то вы сможете исправить их и запустить тест снова. В итоге вы будете уверены, что все целевые браузеры поддерживаются, так как все они прошли тестирование.

    Как писать тесты модулей в QUnit

    Итак, как же непосредственно писать тесты модулей в QUnit? Первым шагом нужно установить среду тестирования:

    Комплект для тестов QUnit Комплект для тестов QUnit

    Код, который будет тестироваться, помещается в файл myProject.js , а тесты помещаются в myTests.js . Чтобы запустить тесты, нужно просто открыть HTML файл в браузере. Теперь пришло время написать какой-нибудь тест.

    Строительным блоком модульного тестирования является утверждение.

    "Утверждение - это выражение, которое прогнозирует возвращаемый результат при выполнении вашего кода. Если прогноз неверный, то утверждение имеет значение false , что позволяет сделать выводы о наличии ошибок."

    Для выполнения утверждений их нужно поместить в блок теста:

    // протестируем данную функцию function isEven(val) { return val % 2 === 0; } test("isEven()", function() { ok(isEven(0), "Ноль - четное число"); ok(isEven(2), "Два - тоже"); ok(isEven(-4), "И отрицательное четыре - тоже четное число"); ok(!isEven(1), "Один - нечетное число"); ok(!isEven(-7), "Как и отрицательное семь - нечетное число"); })

    Здесь мы определяем функцию isEven , которая проверяет четность числа, и хотим убедиться, что данная функция не возвращает ошибочных значений.

    Сначала мы вызываем функцию test() , которая строит блок теста. Первый параметр является строкой, которая будет выводиться в результате. Второй параметр - возвратная функция, которая содержит наши утверждения. Данная возвратная функция будет вызываться один раз при выполнении QUnit.

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

    Вот что мы получим после выполнения теста:

    Все наши утверждения успешно подтвердились, поэтому можно считать, что функция isEven() работает так, как ожидалось.

    Давайте посмотрим, что случиться, если утверждение будет неверным.

    // протестируем данную функцию function isEven(val) { return val % 2 === 0; } test("isEven()", function() { ok(isEven(0), "Ноль - четное число"); ok(isEven(2), "Два - тоже"); ok(isEven(-4), "И отрицательное четыре - тоже четное число"); ok(!isEven(1), "Один - нечетное число"); ok(!isEven(-7), "Как и отрицательное семь - нечетное число"); // Ошибка ok(isEven(3), "Три - четное число"); })

    И вот что мы получим в результате выполнения теста:


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

    Другие утверждения

    ok() не является единственным утверждением, которое поддерживает QUnit. Существуют и другие типы утверждений, которые удобно использовать при составлении тестов для ваших проектов:

    Утверждение сравнения

    Утверждение сравнения equals() предполагает, что первый параметр (который является действительным значением) эквивалентен второму параметру (который является ожидаемым значением). Данное утверждение очень похоже на ok() , но выводит оба значения - действительное и предполагаемое, что существенно облегчает отладку кода. Также как и ok() , equals() в качестве третьего параметра может принимать сообщение для вывода.

    Так вместо

    Test("assertions", function() { ok(1 == 1, "один эквивалентно одному"); })


    Следует использовать:

    Test("assertions", function() { equals(1, 1, "один эквивалентно одному"); })


    Обратите внимание, что в конце строки выводится предполагаемое значение.

    А если значения не равны:

    Test("assertions", function() { equals(2, 1, "один эквивалентно одному"); })


    Такая запись дает больше информации.

    Утверждение сравнения использует оператор “==” для проверки параметров, поэтому оно не может работать с массивами или объектами:

    Test("test", function() { equals({}, {}, "ошибка, это разные объекты"); equals({a: 1}, {a: 1} , "ошибка"); equals(, , "ошибка, это разные массивы"); equals(, , "ошибка"); })

    Для таких случаев в QUnit есть утверждение идентичности.

    Утверждение идентичности

    Утверждение идентичности same() использует те же параметры, что и equals() , но работает не только с примитивными типами, а и с массивами и объектами. Утверждения из предыдущего примера пройдут проверку, если изменить из на утверждения идентичности:

    Test("test", function() { same({}, {}, "проходит, объекты имеют одинаковый контент"); same({a: 1}, {a: 1} , "проходит"); same(, , "проходит, массивы имеют одинаковый контент"); same(, , "проходит"); })

    Заметьте, что same() использует оператор ‘===’ для сравнения, поэтому его удобно использовать для сравнения специальных значений:

    Test("test", function() { equals(0, false, "true"); same(0, false, "false"); equals(null, undefined, "true"); same(null, undefined, "false"); })

    Структура утверждений

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

    Можно организовывать отдельные модули с помощью вызова функции module :

    Module("Модуль A"); test("Тест", function() {}); test("Еще один тест", function() {}); module("Модуль B"); test("Тест", function() {}); test("Еще один тест", function() {});


    В предыдущем примере все утверждения вызывались синхронно, то есть выполнялись одно за другим. В реальном мире существует множество асинхронных функций, таких как запросы AJAX или функции setTimeout() и setInterval() . Как нам тестировать такой тип функций? QUnit имеет специальный тип тестов, который называется "асинхронный тест" и предназначен для асинхронного тестирования:

    Сначала попробуем написать тест обычным способом:

    Test("Асинхронный тест", function() { setTimeout(function() { ok(true); }, 100) })


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

    Правильный вариант тестирования нашего примера:

    Test("Асинхронный тест", function() { // Переводим тест в режим "пауза" stop(); setTimeout(function() { ok(true); // После вызова утверждения // продолжаем тест start(); }, 100) })


    Мы использовали функцию stop() для остановки теста, а после выполнения утверждения снова запускали тест с помощью функции start() .

    Вызов функции stop() сразу после вызова функции test() является весьма распространенной практикой. Поэтому QUnit имеет специальное сокращение: asyncTest() . Предыдущий пример можно переписать в виде:

    AsyncTest("Асинхронный тест", function() { // Тест автоматически переводится в режим "пауза" setTimeout(function() { ok(true); // После вызова утверждения // продолжаем тест start(); }, 100) })

    Есть один момент, над которым стоит задуматься: функция setTimeout() всегда вызывает свою возвратную функцию, а если тестировать другую функцию (например, вызов AJAX). Как быть уверенным, что возвратная функция будет вызвана? Если возвратная функция не будет вызвана, функция start() тоже останется без вызова и весь тест "подвиснет":


    Можно организовать тест следующим образом:

    // Пользовательская функция function ajax(successCallback) { $.ajax({ url: "server.php", success: successCallback }); } test("Асинхронный тест", function() { // Останавливаем тест и // будем сообщать об ошибке, если функция start() не будет вызвана по истечении 1 секунды stop(1000); ajax(function() { // ...асинхронное утверждение start(); }) })

    В функцию stop() передается значение таймаута. Теперь QUnit получил указание: “если функция start() не будет вызвана по истечении таймаута, следует считать данный тест проваленным”. Теперь весь тест не "подвиснет" и будет выдано предупреждение, если что-то пойдет не так, как нужно.

    Теперь рассмотрим случай множественных асинхронных функций. Где размещать функцию start() ? Нужно размещать ее в функции setTimeout() :

    // Пользовательская функция function ajax(successCallback) { $.ajax({ url: "server.php", success: successCallback }); } test("Асинхронный тест", function() { // Останавливаем тест stop(); ajax(function() { // ...асинхронное утверждение }) ajax(function() { // ...асинхронное утверждение }) setTimeout(function() { start(); }, 2000); })

    Значение таймаута должно быть достаточным для выполнения вызовов обеих возвратных функций перед продолжением теста. Если одна из функций не будет вызвана, как определить какая именно? Для этого есть функция expect() :

    // Пользовательская функция function ajax(successCallback) { $.ajax({ url: "server.php", success: successCallback }); } test("Асинхронный тест", function() { // Останавливаем тест stop(); // Сообщаем QUnit, что мы ожидаем выполнения трех утверждений expect(3); ajax(function() { ok(true); }) ajax(function() { ok(true); ok(true); }) setTimeout(function() { start(); }, 2000); })

    Мы передаем в функцию expect() количество утверждений, которые планируется выполнить. Если одно из утверждений не будет выполнено, вы получите сообщение о том, что-то идет не так, как планируется.

    Есть коротка запись для использования expect() : нужно передать количество планируемых утверждений в качестве второго параметра test() или asyncTest() :

    // Пользовательская функция function ajax(successCallback) { $.ajax({ url: "server.php", success: successCallback }); } // Сообщаем QUnit, что мы ожидаем выполнения 3 утверждений test("asynchronous test", 3, function() { // Останавливаем тест stop(); ajax(function() { ok(true); }) ajax(function() { ok(true); ok(true); }) setTimeout(function() { start(); }, 2000); })

    Заключение

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

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

    Этот процесс должен включать комплекс средств контроля качества и эффективности работы программиста. Такими средствами могут быть: модульное и интеграционное тестирование, непрерывная интеграция (Continuous Integration, CI), сбор и анализ разнообразных метрик (например, очень длинные методы в nDepend), проверка на соответствие требованиям JsLint, FxCop и пр.

    В данной статье я хочу рассказать, как правильно выполнять автоматическое модульное и интеграционное тестирование вашего продукта на языке JavaScript. На самом деле в этом плане язык JavaScript ничем кардинально не отличается от Java или С#.

    Agile, TDD и BDD

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

    Существуют также методики программирования, которые требуют начинать кодирование логики с написания модульного теста: Test-Driven Development (TDD) и Behavior-Driven Development (BDD). Они часто используются в Agile-процессе. Рассмотрим их особенности подробнее.

    Test-Driven Development

    Разработка через тестирование — это итеративный процесс написания кода, в котором повторяются следующие четыре шага :

    Шаг 1 . Перед тем, как добавить новый фрагмент логики, создайте модульный тест для проверки этой логики;

    Шаг 2 . Запустите тест и убедитесь в том, что он не проходит;

    Шаг 3 . Напишите самый простой код, который заставит тест выполниться успешно;

    Шаг 4 . Отредактируйте код в соответствии с требованиями к качеству, уберите дублирование кода и убедитесь в том, что тест проходит успешно.

    Под модульным тестом понимается код, который тестирует работу некоторого компонента (модуля) в изолированной среде. Под интеграционным тестом понимается код, который тестирует совместную работу нескольких компонентов. Чтобы протестировать модуль в изолированной среде в случае, когда он зависит от других модулей, применяются «дублёры» (test doubles).

    Test Doubles

    Деление вспомогательных объектов, используемых при модульном тестировании, на категории берёт своё начало с книги xUnit Test Patterns Жерара Мезароса (Gerard Meszaros). Эти категории обобщённо называются «тестовые дублёры» (test doubles). Дублёры бывают следующих видов:

    • Fake;
    • Dummy.

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

    Mock — это вспомогательный объект, поведение которого задаётся заранее. Он используется для того, что имитировать интерфейс зависимого компонента и проверить в ходе теста, правильно ли он используется.

    Spy — это вспомогательный объект для инспектирования вызываемых методов и передаваемых им параметров в ходе теста.

    Fake — это вспомогательный объект, реализующий интерфейс зависимого компонента в упрощённом виде. Например, для целей модульного тестирования можно завести базу данных в памяти вместо реляционной базы данных, которая используется в рабочей версии продукта.

    Dummy — это вспомогательный объект, указание или передача которого требуется сигнатурой метода или любым другим контрактом, но реальное значение никогда не используется.

    Разница между Stub и Mock заключается в способе проверки результатов работы теста. В случае со Stub в конце теста проверяется состояние объекта. В случае с Mock в ходе теста проверяется то, что объект используется именно так, как было описано при регистрации. Подробности можно узнать из заметки Mocks Aren"t Stubs Мартина Фаулера (Martin Fowler), а я приведу тут лишь пример.

    Stub Mock
    "test connect should start polling": function () { this.client.url = "/my/url"; sinon.stub(ajax, "poll").returns({}); this.client.connect(); sinon.assert.calledWith(ajax.poll, "/my/url"); } "test connect should start polling": function () { this.client.url = "/my/url"; var mock = sinon.mock(ajax) mock.expects("poll") .withArgs("/my/url") .returns({}); this.client.connect(); mock.verify(); }
    Behavior-Driven Development

    Итерационный подход к разработке программного обеспечения через реализацию функциональных требований — это уже знакомый нам стиль разработки через тестирование, ориентированный на результат. В процессе BDD последовательно выполняются следующие три шага :

    Шаг 1 . Определение функциональных требований к реализуемому модулю в виде тестов;

    Шаг 2 . Кодирование модуля;

    Шаг 3 . Проверка того, что все пожелания заказчика или бизнес-аналитика () выполнены путем проверки результатов запуска тестов.

    При написании тестов в стиле BDD очень удобно использовать Mock-объекты из-за того, что они отлично отражают требования по функциональной части для компонента. Таким образом, тесты в процессе BDD могут служить формализованным представлением задачи (user story ) в терминах Scrum , что позволяет экономить время на написании технического задания и документации по готовому продукту.

    Каким должен быть фреймворк для модульного тестирования JavaScript?

    Полноценный инструмент для модульного и интеграционного тестирования JavaScript должен состоять из следующих компонентов:

    • Assertion library (набор методов для проверки состояния компонента в конце каждого теста);
    • Mock library (инструмент для генерации Mock-объектов и других "дублёров");
    • Test runner (инструмент автоматического запуска тестов с поддержкой большинства браузеров, включая браузеры iOS и Android);
    • Блока подключения к популярным системам непрерывной интеграции (Continuous Integration).
    Стратегии модульного тестирования кода на языке JavaScript

    Сегодня существует три стратегии модульного тестирования JavaScript кода (подробнее — в третьей главе книги Test-Driven JavaScript Development Кристиана Йохансена (Christian Johansen)):

    • In-Browser тестирование;
    • Headless тестирование;
    • Тестирование по пути JsTestDriver .

    In-Browser тестирование предполагает запуск всех модульных и интеграционных тестов из HTML-страницы, которую разработчик открывает в нужных браузерах самостоятельно. Такой подход прост и интуитивно понятен. Однако его минусом является то, что он не предусматривает возможности включения подобных тестов в Continuous Integration. Кроме того, запускать вручную HTML-страницу в десяти и более браузерах и постоянно нажимать "F5" может быть утомительно для разработчика.

    Headless тестирование заключается в том, что весь JavaScript код тестируется на эмуляторе, который может быть написан на Java, Ruby, JavaScript, C++ и т.д. Самым известным эмулятором на сегодняшний день является PhantomJS , который представляет собой движок WebKit , запускаемый из командной строки. Из преимуществ эмулятора можно отметить то, что его легко можно использовать в Continuous Integration, а также то, что он позволяет автоматизировать запуск всех тестов из командной строки. Однако у такого подхода есть существенный недостаток — код не тестируется на реальных браузерах, поэтому есть риск пропустить ошибки браузера, которые не воспроизводятся на эмуляторе. До появления JsTestDriver можно было часто встретить то, что In-Browser тестирование комбинируется с Headless тестированием, поскольку они прекрасно дополняют друг друга.


    © 2024
    zane-host.ru - Программы. Компьютеры. Сетевое оборудование. Оргтехника