Моя первая цель для WordPress редакционный календарь заключается в том, чтобы сделать его сделать что-нибудь полезное. Я был новичком в JavaScript и PHP и не знаю, что я мог бы снять. Через несколько дней у меня было доказательство концепции. В несколько больше я имел рабочую версию и просил друзей установить его. Календарь работал… Типа.
Дальнейшее чтение на SmashingMag:
- Как коммерческие разработчики Плагина используют репозиторий WordPress
- Общие WordPress вредоносных инфекций
- Управление событиями, как профессионал с WordPress
- Полезные бесплатные плагины для WordPress
Я потратил в три раза больше времени на исправление ошибок, чем кодирование. После того, как плагин работал, я написал модульные тесты, чтобы убедиться, что он продолжал работать.
Модульные тесты для моего календаря используют «Unit»,но на самом деле они используют только три функции: test
expect
и ok
. Эта статья показывает вам, как интегрировать модульные тесты в плагин WordPress, где писать модульные тесты и как они могут помочь вам.
«Основы иединоката»
Единие тесты следовать основной схеме: сделать что-то, а затем проверить результаты. («Является ли эта переменная, 4
когда она должна 5
быть?» «Неужели эта линия моего стола показать, где он должен?»)
function myTest() {
test('My test run', function() {
expect(2);
ok(5 === 5, 'This test will always pass');
ok(5 === 6, 'This test will always fail');
});
}
Эта структура заставляет вас думать о вашем коде в простых единиц, которые возвращаются true
или false
. test
Функция запускает тестовый запуск с двумя аргументами: название для этого тестового запуска и функция, содержащая тесты. expect
Функция сообщает « Unit, сколько тестов в беге. Если мы называем слишком мало или слишком много, это вызывает ошибку.
ok
Функция выполняет тест выражения. Требуется два аргумента: булей, указывающий на то, был ли тест успешным, и сообщение.
Тестовые запуски добавляются в специальный раздел списка, который показывает общее количество тестов, пройдено или не удав или не выполняется, и сколько времени заняли тесты.
Испытание реального блока
Плагины WordPress усложняют тестирование, используя комбинацию PHP и JavaScript. Даже передача простого значения от PHP до JavaScript становится сложной.
Функция ниже находит предпочтение WordPress с get_option
функцией и создает переменную JavaScript с полученным значением.
function getOption($myOption, $myVariable) {
if (get_option($myOption) != "") {
?><script type="text/javascript">
<?php echo($myVariable); ?> = <?php echo(get_option($myOption)); ?>;
<php
}
}
Теперь мы назовем его, чтобы получить название блога и установить его на переменную под названием myBlogName
.
getOption("blogname", "myBlogName");
Маленький помощник функции, как эти клей ваш плагин вместе, но они всегда беспокоят меня. Получил ли я доступ к переменной JavaScript с правильным именем или неправильно ее впечатлял? Я использовал одно и то же имя дважды? Простой модульный тест делает все эти заботы уйти.
function wpPrefTest() {
test('Get access to WordPress preferences', function() {
expect(1);
ok(myBlogName, 'The variable (myBlogName) should be available.');
});
}
Этот модульный тест myBlogName
проверяет, существует ли переменная. Мы также могли бы посмотреть на определенное значение или сравнить его с чем-то еще из приложения.
Если у вас есть этот модульный тест, вам никогда не придется беспокоиться о получении названия блога. Он всегда будет там, и вы узнаете быстро, если вы когда-нибудь разорвать его.
Интеграция «Унит с WordPress»
Тестирование в специальных средах разработки не является точным. Я хотел добавить «Unit» непосредственно в свой календарь, но я не хотел делать размер страницы больше. Решение является параметром URL и немного PHP включить «Unit только тогда, когда мне это нужно:
wp_enqueue_script( "qunit", path_join(WP_PLUGIN_URL, basename( dirname( __FILE__ ) )."/lib/qunit.js"), array( 'jquery' ) );
wp_enqueue_script( "edcal-test", path_join(WP_PLUGIN_URL, basename( dirname( __FILE__ ) )."/edcal_test.js"), array( 'jquery' ) );
Это говорит WordPress включить «Унит JavaScript edcal_test.js
и мои испытания блока от . Я мог бы просто встроенные ссылки скрипта непосредственно на моей странице, но я, возможно, столкнулись с проблемами, если другие плагины на той же странице использовать «Unit.
Вы можете увидеть полный исходный код здесь.
Следующим шагом было убедиться, что эти скрипты загружаются только тогда, когда они мне нужны. Для этого я завернул код в чек на параметр URL:
if ($_GET['qunit']) {
wp_enqueue_script( "qunit", path_join(WP_PLUGIN_URL, basename( dirname( __FILE__ ) )."/lib/qunit.js"), array( 'jquery' ) );
wp_enqueue_script( "edcal-test", path_join(WP_PLUGIN_URL, basename( dirname( __FILE__ ) )."/edcal_test.js"), array( 'jquery' ) );
}
Это загружает скрипты только в том случае, если я запускаю модульные тесты, а все остальное в плагине остается неизменным. Вы можете запустить модульные тесты в любое время, просто добавив &qunit=true
к концу URL-адреса. Это хорошо, потому что мой блок испытаний на самом деле изменить то, что происходит в блоге.
Вы можете запустить модульные тесты редакционного календаря в браузере прямо сейчас. Прокрутите вниз, чтобы увидеть результаты теста единицы в нижней части страницы.
PHP гарантирует, что мои скрипты попадают в браузер. Последним шагом является вызов их из моего JavaScript. Еще раз, я хочу позвонить им, только если мы находимся в режиме модульного теста. Итак, я добавляю небольшую функцию, чтобы получить параметры из URL:
getUrlVars: function() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
А потом я называю мои модульные тесты, если параметр «Unit» есть:
jQuery(document).ready(function() {
if (edcal.getUrlVars().qunit) {
edcal_test.runTests();
}
});
Это гарантирует, что мы вызываем модульные тесты только в том случае, если они доступны.
Последним шагом является настройка пространства для вывода модульного теста. «Unit записывает свои результаты теста в специально назначенные теги на вашей странице HTML. Эти теги можно вставлять непосредственно в вывод HTML, но поскольку они должны быть там только тогда, когда «Unit активен», я создаю HTML в JavaScript.
jQuery('head').append('<link>');
css = jQuery('head').children(':last');
css.attr({
rel: 'stylesheet',
type: 'text/css',
href: '../wp-content/plugins/edcal/lib/qunit.css'
});
jQuery('#wpbody-content .wrap').append('<div id="edcal-qunit"></div>');
jQuery('#edcal-qunit').append(
'<h1 id="qunit-header">WordPress Editorial Calendar Unit Tests</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>');
«Unit нуждается в теге списка, паре divs и листе типа.
Теперь мы готовы написать наш первый тест.
Тест первого блока
Первые модульные тесты календаря прокрутки календаря вверх и вниз и убедитесь, что мы видим правильное количество дней.
moveTests: function() {
var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
edcal.moveTo(Date.today());
test('Move to today and check visible dates', function() {
expect(2);
ok(edcal_test.getFirstDate().equals(curSunday.clone()),
'firstDate should match ' + curSunday);
ok(edcal_test.getLastDate().equals(
curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days()),
'lastDate should match ' + curSunday);
});
}
Наш первый тест перемещает календарь на сегодняшний день и проверяет, если первый и последний дни, что мы ожидаем. Мы настраиваем переменную, переносим календарь и запускаем тест, вызывая test
функцию.
В этом случае мы хотим убедиться, что даты верны, поэтому мы сравниваем дату из календаря с той, что мы ожидаем, и затем передать результат ok
функции. Тест удается, если они совпадают и не удается, если они этого не делают.
Этот тест может показаться простым, но многое происходит под капотом. Мы тестируем обработку дат, рисование и фундаментальную арифметику календаря.
Единие тесты могут делать все. WordPress Редакционный календарь единицы автоматизации плагина, как робот. Они охватывают все, что пользователь может сделать с календарем.
Что с единым тестом
Я пишу гораздо больше модульных тестов для JavaScript, чем для компилированных языков. В Java и C,, компилятор ловит многие из моих ошибок, в то время как JavaScript позволяет пройти, string
когда вы хотели пройти и позволяет number
вызвать функцию с двумя аргументами, когда она нуждается в трех.
Вот основной список областей, которые я тестирной в JavaScript приложений:
- Тесты, которые убедитесь, что программа делает то, что она предназначена для этого. Эти тесты гарантируют, что основная функциональность продолжает работать; они не тестируют взаимодействия. (Календарь позволяет перетащить и упасть сообщения, но написание модульных тестов для перетаскивания и падения не имеет смысла; вместо этого, мы сосредоточимся на том, что происходит после события падения.)
- Тесты, которые убедитесь, что программа не делает то, что она не предназначена для этого Эти тесты гарантируют, что программа выходит из строя должным образом, когда она получает мусор.
- Модульный тест для каждой найденной ошибки Эти тесты гарантируют, что ни одна из этих ошибок не вернется.
AA и другие четкие границы кода хорошо поддаются модульным тестам, как и утилита функций, которые вы называете из многих мест в приложении. С календарем это означает тестирование движений календаря и тестирование того, как мы создаем и модифицируем сообщения в WordPress, как это:
- Переместить календарь и проверить даты;
- Создайте публикацию и убедитесь, что он был создан должным образом;
- Изменить сообщение мы только что создали и убедитесь, что он сохраняет должным образом;
- Переместите сообщение и убедитесь, что он отображается в нужное время;
- Перемещение поста из двух мест в то же время и убедитесь, что мы получаем надлежащее сообщение предупреждение;
- Удалите сообщение с сервера и убедитесь, что он не существует больше.
Предпоследний тест охватывает условие ошибки, при котором два человека перемещают один и тот же пост одновременно. Единие тесты хорошо работают для такого рода ошибок, потому что тип ошибки трудно проверить и ручного тестирования с меньшей вероятностью выявить проблемы.
Для собственного приложения необходимо иметь по крайней мере один модульный тест для каждой операции, изменяющей данные, которую могут выполнять пользователи. Я хотел бы добавить их для всех мест, где пользователь может получить данные, тоже. Это может звучать как много работы, но вы можете сократить его, написав одиночные тесты, которые охватывают несколько областей.
Асинхронные модульные испытания
Многие из этих комбинированных модульных тестов делают ajax вызовы. «Unit предоставляет специальную функцию для обработки AJAX под названием asyncTest
. Эта функция работает так test
же, как, но она приостанавливает тестовый запуск в конце функции. Платформа «Unit» ждет завершения вызова AJAX и вызова start
функции перед перезапуском тестового запуска.
asyncTest
Функция обрабатывает все тесты, которые отсеивают сообщения из календаря, включая удаляние публикации в конце:
asyncTest('Delete the post created for testing', function() {
expect(1);
edcal.deletePost(edcal_test.post.id, function(res)
{
equals(jQuery('#post-' + res.post.id).length, 0,
'The post should now be deleted from the calendar.');
start();
});
});
При перезагрузке тестовой инфраструктуры можно вызвать дополнительные тесты. Вызов следующей тестовой функции в конце предыдущей цепочки их вместе, и он поддерживает вызов всех ваших тестов только с вызовом к первой функции.
Эти тесты, которые называются AJAX, гарантируют, что интеграция между JavaScript на стороне клиента и PHP на задней части работает должным образом.
Это не единичный тест
Когда я впервые научился писать модульные тесты в СЗ, правило было таково: один тест должен вызывать код только в одном модуле или файле CPP. То есть модульный тест должен протестировать одну единицу кода.
Изменение сообщений из модульных тестов нарушает это правило. Вместо того, чтобы просто тестирование JavaScript, я действительно тестирования JavaScript, PHP, WordPress себя и MyS’L все сразу. Это делает его автоматизированным тестом интеграции.
Интеграционные тесты не являются традиционными модульными тестами, но они хорошо работают для плагинов WordPress. Когда я создаю публикацию, я буду знать, что код AJAX в моем плагине работает так же, как код JavaScript. Охват большая часть приложения с меньшим количеством тестов облегчает фокусировку на том, что я должен тестировать.
Что не в единицу теста
Вы можете писать модульные тесты навсегда, но некоторые из них более полезны, чем другие. Вот некоторые рекомендации.
- Не проверяйте uI. Тест должен быть запущен сам по себе. Он не может ждать, пока вы нажмете кнопку или посмотреть на что-то, чтобы убедиться, что он появляется правильно.
- Не уединица тестовой производительности. Тесты занимают различное количество времени на разных машинах и браузерах. Не пишите модульные тесты, которые зависят от возвращаемых функций за определенное количество времени.
- Не объединяйте тестовый код из других проектов. Добавление модульных тестов для WordPress или плагина j’sin, от чего вы зависите, может быть заманчивым, но это редко окупается. Если вы хотите внести модульные тесты, чтобы WordPress.org это здорово, но ваши модульные тесты должны проверить, работает ли ваш плагин.
Редакционный календарь имеет 26 модульных тестов, около 3500 строк кода. Это не может звучать как много, но они сохранили многие из моих релизов.
Единие испытаний спас логово мое прикладом
Я не добавлял модульные тесты до тринадцатого выпуска моего плагина. К тому времени, календарь имел пару сотен пользователей и быстро рос. Мой плагин работал, и я был близок к выпуску 1.0.
Вместо добавления новых функций, я взял в новой структуре, добавил специальный код для его загрузки, написал 381 линии модульных тестов и интегрировал все это в плагин. Кажется, много работы, но это спасло мою задницу.
Прямо перед выпуском, я написал некоторые безобидные перспективных PHP код, как следующие, чтобы получить данные JSON, которые представляли собой набор сообщений, чтобы показать в календаре:
function edcal_postJSON($post) {
setup_postdata($post);
?>
{
"date" : "<?php the_time('d') ?><?php the_time('m') ?><?php the_time('Y') ?>",
"title" : <?php echo($this->edcal_json_encode(get_the_title())); ?>,
"author" : <?php echo($this->edcal_json_encode(get_the_author())); ?>
},
<?php
}
function edcal_posts() {
header("Content-Type: application/json");
global $post;
$args = array(
'posts_per_page' => -1,
'post_status' => "publish&future&draft",
'post_parent' => null // any parent
);
$myposts = query_posts($args);
?>[
<?php
$size = sizeof($myposts);
for($i = 0; $i < $size; $i++) {
$post = $myposts[$i];
edcal_postJSON($post, $i < $size - 1);
}
?> ]
<?php
}
Я проверила код, и все сработало. Я собирался выпустить новую версию, но побежал мой модуль испытаний первым, чтобы убедиться. Они потерпели неудачу. Можете ли вы обнаружить ошибку? Я не сделал.
Я возвращал массив JSON, но последний пункт в массиве имел задняя запятая. Это недействительно JSON. Firefox принимает его, но Safari, Chrome и IE нет. Я почти поставляется сломанной плагин для более чем половины моих пользователей.
Теперь я запускаю модульные тесты на всех основных браузерах всякий раз, когда я выпускаю новую версию. Каждый раз, когда WordPress выпускает новую версию, я запускаю модульные тесты. WordPress 3.3 сломал календарь — и я узнал, почему именно в 15 секунд.
Популярные плагины стабильны плагины
Большинство Плагинов WordPress являются бесплатными и с открытым исходным кодом, но бесплатно не всегда означает дешево. Общая стоимость владения нестабильными плагинами больше, чем люди будут платить. Это причудливый способ сказать, что пользователи будут работать с вашего плагина, если это ошибка фестиваля.
Мой плагин стал популярным из-за его особенностей, но стабильность держала его популярным. Люди помнят один багги релиз в течение длительного времени. Если редакционный календарь удаляет или развращает сообщения из одного блога, тысячи людей перестанут его использовать. И они были бы оправданы.
Единичные тесты добавляют стабильность, необходимую для поддержки множества браузеров, мобильных устройств и темных углов, участвующих в любом приложении JavaScript. Они легко писать, и они платят вам обратно: потому что вы найдете ошибки, и ваши пользователи этого не делают.
Источник: smashingmagazine.com