Я собираюсь рассказать об одной из тем, касающихся Apache Cordova, которая практически не освещена в рунете — как тестировать свой плагин для Apache Cordova.
В рамках этой статьи мы будем тестировать только JavaScript код, поскольку такие тесты довольно легко внедрить и зачастую их будет достаточно. Конечно, как правило, плагины содержат и нативный код для каждой из поддерживаемых платформ, который тоже неплохо было бы покрыть unit-тестами, но мы пока оставим этот вопрос за кадром, поскольку этот аспект тестирования плагинов практически не распространен и отсутствует какой-либо инструментарий для такого тестирования. В любом случае, код JavaScript, как правило, вызывает нативную логику, и поэтому наши тесты будут косвенно тестировать и реализацию под каждую платформу.
Немного теории
Итак, каким образом осуществляется тестирование плагинов для Apache Cordova. Прежде всего, архитектура тестов состоит из двух частей:
- Собственно тесты, использующие ту или иную библиотеку для тестирования.
- Так называемая test harness, или часть кода ответственная за запуск тестов и генерацию результатов теста.
В случае с плагинами в качестве библиотеки используется BDD-фреймворк Jasmine — довольно популярный в JavaScript мире. Соответственно будущие тесты могут выглядеть примерно так (отрывок взят из тестов для cordova-plugin-device
— одного из плагинов, поддерживаемых сообществом Apache Cordova):
it("should exist", function() { expect(window.device).toBeDefined(); }); it("should contain a platform specification that is a string", function() { expect(window.device.platform).toBeDefined(); expect((new String(window.device.platform)).length > 0).toBe(true); }); it("should contain a version specification that is a string", function() { expect(window.device.version).toBeDefined(); expect((new String(window.device.version)).length > 0).toBe(true); });
Если с кодом тестов все достаточно ясно и понятно, то для того чтобы их запустить, необходимо проделать дополнительные манипуляции.
Самым простым способом здесь будет использование cordova-plugin-test-framework
— еще одного плагина, который добавляет в приложение интерфейс для запуска тестов в виде отдельной страницы с элементами управления для запуска, остановки и выбора тестов для запуска, а так же осуществляет загрузку всех объявленных тестов во время работы приложения и их запуск.
Вот как это выглядит в работе:
Кроме того test-framework
предоставляет возможность быстро создать т.н. ручные тесты — создать несколько кнопок на отдельной странице с описанием действий связанных с нажатием на каждую кнопку и ожидаемого поведения приложения.
README плагина описывает, как он работает и как нужно добавлять тесты, чтобы test-framework
подхватил их, однако содержит некоторые неточности, поэтому вкратце приведу основные тезисы здесь.
- Для объявления тестов их нужно выделить в отдельный плагин. Расположение плагина не критично, но часто он находится внутри подпапки
/tests
основного плагина. - Сами тесты должны находиться в модуле с именем, оканчивающимся на
tests
, (например<js-module src="tests/tests.js" name="my.plugin.tests">
) - Модуль с тестами должен экспортировать две функции:
exports.defineAutoTests = function() { }; exports.defineManualTests = function(contentEl, createActionButton) {};
которые будут выполнены при загрузке модуля. Название функций говорит само за себя.
- Полезно так же будет добавить
cordova-plugin-test-framework
— а возможно еще и тестируемый плагин — в качестве зависимости для ваших тестов, чтобы они устанавливались автоматически вместе с тестами. Это делается добавлением следующих элементов вtests/plugin.xml
:
<dependency id="cordova-plugin-test-framework"/> <dependency id="my-awesome-plugin" url=".." />
Создаем каркас плагина
Итак, после того, как все подготовлено для написания, каркас плагина должен выглядеть примерно следующим образом:
plugin.xml
будет выглядеть так:
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="my-awesome-tests" version="0.0.1"> <name>My Awesome Plugin Tests</name> <dependency id="cordova-plugin-test-framework" /> <dependency id="my-awesome-plugin" url=".." /> <js-module src="tests.js" name="tests" /> </plugin>
tests.js
:
exports.defineAutoTests = function() { // To be done }; exports.defineManualTests = function(content, createActionButton) { // To be done };
Это можно сделать вручную в вашем $EDITOR
, а можно использовать plugman
— еще один инструмент для работы с плагинами Apache Cordova:
npm install -g plugman plugman create --name "My awesome plugin tests" --plugin_id my-awesome-plugin-tests --plugin_version 0.0.1 --path=./tests
чтобы сгенерировать каркас плагина и отредактировать файлы вручную.
Пишем автоматические тесты
Теперь перейдем непосредственно к написанию тестов. Те кто уже знакомы с BDD и jasmine могут пропустить этот раздел, т.к. ничего нового здесь не будет, и перейти к следующему.
Примеры далее в этой статье основаны на простом плагине, написанном за 10 минут в демонстрационных целях. Код плагина можно найти на GitHub.
Итак, сначала создаем каркас тестового плагина, как описано в предыдущем разделе и начинаем наполнять его тестами.
exports.defineAutoTests = function() { describe('plugin', function() { it('should be exposed as cordova.plugins.MyAwesomePlugin object', function() { expect(cordova.plugins.MyAwesomePlugin).toBeDefined(); expect(cordova.require('my-awesome-plugin.MyAwesomePlugin')) .toBe(cordova.plugins.MyAwesomePlugin); }); it('should have corresponding methods defined', function() { ['coolMethod', 'logCoolMessage'].forEach(function(methodName) { expect(cordova.plugins.MyAwesomePlugin[methodName]).toBeDefined(); expect(cordova.plugins.MyAwesomePlugin[methodName]).toEqual(jasmine.any(Function)); }); }); }); };
Пока этого достаточно. Теперь создадим тестовое приложение и запустим наши тесты. Для этого выполняем следующие команды в папке с тестируемым плагином:
cordova create my-sample-app && cd my-sample-app cordova platform add android --save cordova plugin add .. ../tests --save
и правим элемент <content src="index.html" />
в файле config.xml
внутри нашего тестового приложения — меняем значение на cdvtests/index.html
. Это необходимо чтобы вместо основной стартовой страницы при запуске приложения открылась страница плагина и загрузился test-framework
.
Теперь запускаем приложение:
cordova run
и видим страницу плагина. Нажимаем "Autotests" и практически сразу видим отчет jasmine об успешном завершении тестов.
Добавляем ручные тесты
Теперь, понимая как работает test-framework
, можно без особых проблем написать любое количество автоматических тестов для вашего плагина.
С ручными тестами все работает немного по-другому. test-framework
предполагает, что каждому тесту полагается отдельная кнопка в интерфейсе и общее для всех тестов поле в которое можно вывести свои результаты. Это параметры createActionButton
и content
соответственно для функции defineManualTests
.
createActionButton
это функция, которая создает кнопку, добавляет ее в DOM внутрь указанного элемента и выполняет указанную функцию при нажатии кнопки. Параметры функции выглядят так:
`function createActionButton('Текст кнопки', выполняемая_функция, 'ИД_элемента') {...}`
content
это контейнер на странице, внутри которого можно поместить информацию о тесте и описать процесс верификации для тестировщика.
Для примера добавим один ручной тест:
exports.defineManualTests = function(contentEl, createActionButton) { var show_preferences_test = '<h3>Press "Open preferences" button to show preferences pane</h3>' + '<div id="open_prefs"></div>' + 'Expected result: A "Preferences" box should appear'; contentEl.innerHTML = '<div id="info"></div>' + show_preferences_test; var log = document.getElementById('info'); var logMessage = function (message) { var logLine = document.createElement('div'); logLine.innerHTML = message; log.appendChild(logLine); }; createActionButton('Open preferences', function() { log.innerHTML = ''; // cleanup log area plugins.appPreferences.show(function(result) { logMessage(result); }, function(error) { logMessage(error); }); }, "open_prefs"); };
Теперь нам нужно пересобрать приложение с обновленным плагином. Для этого просто удалим плагин из приложения и попробуем запустить приложение.
cordova plugin rm my-awesome-plugin-tests && cordova run
Команда run
перед сборкой приложения восстановит удаленный плагин из его первоначального местоположения вместе с обновленными файлами, и все изменения будут включены в приложение.
Запускаем тесты на CI
Пересобирать приложение для того чтобы запустить тесты еще раз — довольно рутинное занятие, которое конечно хочется делать автоматически. Вместо того чтобы изобретать собственный велосипед, воспользуемся готовым решением — cordova-paramedic
. Это приложение написано специально для того чтобы автоматизировать запуск тестов для плагинов в т.ч. и для CI. Вот что оно делает:
- создает новое приложение во временной папке
- добавляет в приложение необходимы для запуска тестов плагины
- изменяет стартовую страницу приложения
- запускает локальный сервер для коммуникации с приложением и обработки результатов
- выводит результат запуска тестов на консоль
- завершается с соответствующим кодом в зависимости от того, прошли ли все тесты успешно или нет.
Для того чтобы начать использовать paramedic
, установим его и добавим в package.json
нашего плагина:
npm install cordova-paramedic --save-dev
и добавим пару команд для запуска тестов для iOS и Android.
"scripts": { ... "test-android": "cordova-paramedic --platform android --plugin ./ --verbose", "test-ios": "cordova-paramedic --platform ios --plugin ./ --verbose" },
Все. Теперь вместо того чтобы собирать приложение вручную, править его config.xml
, запускать и потом смотреть как появляются точки и крестики пройденных и упавших тестов просто запускаем соответствующий скрипт, например для Android:
npm run test-android
И через некоторое время получаем результаты тестов на консоль:
... Results: ran 2 specs with 0 failures result code is : 0 {"mobilespec":{"specs":2,"failures":0,"results":[]},"platform":"Desktop","version":"5.1.0","timestamp":1455530481,"model":"none"}
Теперь становится очень просто запускать тесты на CI-машине. Возьмем для примера Travis CI и Circle CI:
.travis.yml
language: objective-c install: - npm install script: - npm run test-ios
circle.yml
test: pre: - emulator -avd circleci-android21 -no-audio -no-window: background: true parallel: true - circle-android wait-for-boot override: - npm run test-android
Затем идем в панель управления соответствующего сервиса, включаем интеграцию с GitHub и наслаждаемся:
Заключение
Итак, теперь мы имеем плагин покрытый автоматическими тестами, умеем создавать и запускать тестовое приложение буквально одной-двумя строчками в терминале, и знаем состояние кода, обновляющееся per-commit.
Напоследок еще раз приведу ссылку на демонстрационный плагин: https://github.com/vladimir-kotikov/my-awesome-plugin. Посмотреть этапы добавления тестов можно по истории коммитов.
Удачного тестирования!
ссылка на оригинал статьи https://habrahabr.ru/post/277615/
Добавить комментарий