В этой статье мы рассмотрим автоматизированное тестирование в Drupal 8. Более конкретно, мы собираемся написать несколько интеграционных тестов для некоторой бизнес-логики, которую мы написали в предыдущих статьях Sitepoint по разработке модулей для Drupal 8. Вы можете найти последнюю версию этого кода в этом хранилище вместе с тестами, которые мы пишем сегодня.
Но перед этим мы немного поговорим о том, какие тесты мы можем написать в Drupal 8 и как они на самом деле работают.
Simpletest (Тестирование)
Simpletest — это специфическая среда тестирования Drupal. Для Drupal 6 это был дополнительный модуль, но начиная с Drupal 7 он был частью основного пакета. Simpletest в настоящее время является неотъемлемой частью разработки ядра Drupal, позволяя безопасно модифицировать API благодаря обширному охвату тестовой базы кода.
Сразу же упомяну официальную страницу документации по тестированию Drupal с Simpletest. Там вы можете найти центр информации о том, как работает Simpletest, как вы можете написать для него тесты, какие методы API вы можете использовать и т. Д.
По умолчанию модуль Simpletest, который поставляется с ядром Drupal, не включен, поэтому нам придется делать это самостоятельно, если мы хотим запускать тесты. Его можно найти на странице «Расширить» с именем « Testing
.
Как только это будет сделано, мы можем перейти к admin/config/development/testing
и просмотреть все тесты, доступные в настоящее время для сайта. К ним относятся тесты как ядра, так и модуля contrib. В самом низу также есть кнопка « Clean environment
, которую мы можем использовать, если какой-либо из наших тестов неожиданно завершился, и в вашей базе данных остались некоторые тестовые таблицы.
Как работает Simpletest?
Когда мы запускаем тест, написанный для Simpletest, последний использует существующую кодовую базу и инструкции, найденные в тесте, чтобы создать отдельную среду Drupal, в которой может выполняться тест. Это означает добавление в базу данных дополнительных таблиц (с префиксом simpletest_
) и тестовых данных, которые используются для репликации экземпляра сайта.
В зависимости от типа теста, который мы выполняем, и от того, что он содержит, характер этой репликации может отличаться. Другими словами, среда может иметь разные данные и основные функциональные возможности в зависимости от самого теста.
Какие тесты есть в Drupal 8?
Существует два основных типа тестов, которые мы можем написать для Drupal 8: модульные тесты с использованием PHPUnit (который сейчас находится в ядре) и функциональные тесты (с использованием Simpletest). Тем не менее, последний также может быть разделен на два разных вида: веб-тесты (которые требуют веб-вывода) и тесты ядра (которые не требуют веб-вывода). В этой статье мы практически охватим только веб-тесты, потому что большая часть функциональности, которую мы написали в предыдущих статьях, проявляется в выводе, так что именно так нам и нужно ее тестировать.
Написание любого типа теста начинается с реализации определенного класса и помещения его в папку src/Tests
того модуля, который он тестирует. Я также призываю вас прочитать эту страницу документации, которая содержит дополнительную информацию по этой теме, поскольку я не хочу дублировать ее здесь.
Наши тесты
Как я уже упоминал, в этой статье мы сконцентрируемся на предоставлении тестового покрытия для некоторой бизнес-логики, которую мы создали в серии по разработке модуля Drupal 8 . Хотя в этом нет ничего сложного, созданный нами demo
модуль является хорошим примером для начала нашего процесса тестирования. Итак, начнем с определения того, что мы будем тестировать.
Посмотрев на демонстрационный модуль , мы можем выделить следующие аспекты, которые мы можем протестировать:
- У нас есть маршрут, который отображает страницу с определенным сообщением, загруженным из службы .
- У нас есть маршрут, который отображает форму и имеет некоторую конфигурацию.
- У нас есть собственный блочный плагин, который мы можем настроить и добавить на страницу.
Вот и все. Пользовательская ссылка меню, которую мы определили внутри demo.links.menu.yml
также может быть протестирована, но она должна работать из коробки, поэтому я предпочитаю этого не делать.
Для краткости и того факта, что нам не нужно слишком много тестировать, я включу все наши методы тестирования в один класс. Тем не менее, вам, вероятно, следует сгруппировать свои группы в несколько классов в зависимости от того, за что они действительно отвечают.
Внутри файла с именем DemoTest.php
расположенного в папке src/Tests/
, мы можем начать с добавления следующего:
<?php namespace Drupal\demo\Tests; use Drupal\simpletest\WebTestBase; /** * Tests the Drupal 8 demo module functionality * * @group demo */ class DemoTest extends WebTestBase { /** * Modules to install. * * @var array */ public static $modules = array('demo', 'node', 'block'); /** * A simple user with 'access content' permission */ private $user; /** * Perform any initial set up tasks that run before every test method */ public function setUp() { parent::setUp(); $this->user = $this->drupalCreateUser(array('access content')); } }
Здесь у нас есть простой тестовый класс, который для каждого запускаемого теста включает модули в свойстве $modules
и создает нового пользователя, хранящегося в свойстве $user
(благодаря запуску setUp()
).
Для наших целей нам нужно включить demo
модуль, потому что это то, что мы тестируем, block
модуль, потому что у нас есть собственный блочный плагин, который мы должны протестировать, и модуль node
потому что наша логика использует разрешение на access content
определенное этим модулем. Кроме того, пользователь создан только для того, чтобы мы могли убедиться, что это разрешение соблюдается.
Для трех указанных выше пунктов мы создадим три метода испытаний. Имейте в виду, что каждый из них должен начинаться с префиксного test
чтобы Simpletest запускал их автоматически.
Тестирование страницы
Мы можем начать с тестирования пользовательского обратного вызова страницы:
/** * Tests that the 'demo/' path returns the right content */ public function testCustomPageExists() { $this->drupalLogin($this->user); $this->drupalGet('demo'); $this->assertResponse(200); $demo_service = \Drupal::service('demo.demo_service'); $this->assertText(sprintf('Hello %s!', $demo_service->getDemoValue()), 'Correct message is shown.'); }
И вот код, который делает это.
Сначала мы авторизируемся с пользователем, которого создали в setUp()
а затем setUp()
к demo
пути. Simpletest обрабатывает эту навигацию, используя собственный внутренний браузер . Далее мы утверждаем, что ответ последней доступной страницы — 200. Это подтверждает, что страница существует. Однако этого недостаточно, потому что мы должны убедиться, что текст, отображаемый на странице, загружен из нашего сервиса.
Для этого мы статически получаем доступ к классу \Drupal
и загружаем наш сервис. Затем мы утверждаем, что страница выводит приветственное сообщение, состоящее из жестко закодированной строки и возвращаемого значения метода getDemoValue()
службы. Вероятно, было бы неплохо написать модульный тест для любой логики, происходящей внутри службы, но для нашего случая это было бы излишним.
И это все с логикой, связанной со страницей. Мы можем перейти на страницу тестирования на нашем сайте, найти только что созданный DemoTest
и запустить его. Если все хорошо, у нас должно быть все зеленое и без сбоев.
Тестирование формы
Для формы у нас есть другой метод, хотя и более мясистый, который проверяет всю необходимую логику:
/** * Tests the custom form */ public function testCustomFormWorks() { $this->drupalLogin($this->user); $this->drupalGet('demo/form'); $this->assertResponse(200); $config = $this->config('demo.settings'); $this->assertFieldByName('email', $config->get('demo.email_address'), 'The field was found with the correct value.'); $this->drupalPostForm(NULL, array( 'email' => '[email protected]' ), t('Save configuration')); $this->assertText('The configuration options have been saved.', 'The form was saved correctly.'); $this->drupalGet('demo/form'); $this->assertResponse(200); $this->assertFieldByName('email', '[email protected]', 'The field was found with the correct value.'); $this->drupalPostForm('demo/form', array( 'email' => '[email protected]' ), t('Save configuration')); $this->assertText('This is not a .com email address.', 'The form validation correctly failed.'); $this->drupalGet('demo/form'); $this->assertResponse(200); $this->assertNoFieldByName('email', '[email protected]', 'The field was found with the correct value.'); }
Первый шаг как прежде. Заходим на страницу формы и подтверждаем успешный ответ. Далее мы хотим проверить, что элемент формы email
существует и что его значение по умолчанию является значением, найденным в конфигурации модуля по умолчанию. Для этого мы используем утверждение assertFieldByName()
.
Еще один аспект, который нам нужно проверить, заключается в том, что сохранение формы с правильным адресом электронной почты делает то, что должно: сохранять электронную почту в конфигурации. Поэтому мы используем метод drupalPostForm()
родительского класса, чтобы отправить форму с правильным адресом электронной почты и заявить, что в результате на странице будет напечатано сообщение об успешном статусе. Это доказывает, что форма успешно сохранена, но не обязательно, что новое письмо было сохранено. Поэтому мы повторяем шаг, который мы сделали ранее, но на этот раз утверждаем, что значением по умолчанию для поля электронной почты является новый адрес электронной почты.
Наконец, нам нужно также проверить, что форма не отправляется с неправильным адресом электронной почты. Мы делаем это снова в два этапа: протестируем ошибку проверки формы при отправке формы и повторная загрузка формы не будет содержать неправильное электронное письмо в качестве значения по умолчанию для поля электронной почты.
Тестирование блока
/** * Tests the functionality of the Demo block */ public function testDemoBlock() { $user = $this->drupalCreateUser(array('access content', 'administer blocks')); $this->drupalLogin($user); $block = array(); $block['id'] = 'demo_block'; $block['settings[label]'] = $this->randomMachineName(8); $block['theme'] = $this->config('system.theme')->get('default'); $block['region'] = 'header'; $edit = array( 'settings[label]' => $block['settings[label]'], 'id' => $block['id'], 'region' => $block['region'] ); $this->drupalPostForm('admin/structure/block/add/' . $block['id'] . '/' . $block['theme'], $edit, t('Save block')); $this->assertText(t('The block configuration has been saved.'), 'Demo block created.'); $this->drupalGet(''); $this->assertText('Hello to no one', 'Default text is printed by the block.'); $edit = array('settings[demo_block_settings]' => 'Test name'); $this->drupalPostForm('admin/structure/block/manage/' . $block['id'], $edit, t('Save block')); $this->assertText(t('The block configuration has been saved.'), 'Demo block saved.'); $this->drupalGet(''); $this->assertText('Hello Test name!', 'Configured text is printed by the block.'); }
Для этого теста нам нужен другой пользователь, который также имеет разрешение на администрирование блоков. Затем мы создаем новый экземпляр нашего пользовательского demo_block
без значения в поле Who
и утверждаем, что в результате будет напечатано успешное подтверждающее сообщение. Далее мы переходим на первую страницу и утверждаем, что наш блок обнаруживается и отображает правильный текст: « Hello to no one
.
Наконец, мы редактируем блок и указываем Test name
в поле « Who
и утверждаем, что сохранение конфигурации блока привело к успешному появлению подтверждающего сообщения. И мы закрываем, возвращаясь к домашней странице, чтобы утверждать, что блок отображает правильный текст.
Вывод
В этой статье мы увидели, как просто написать несколько базовых интеграционных тестов для нашей бизнес-логики Drupal 8. Он включает в себя создание одного или нескольких файлов классов, которые просто используют большой набор методов и утверждений API для проверки правильности поведения нашего кода. Я настоятельно рекомендую вам попробовать и начать тестировать свой пользовательский код как можно раньше, чтобы сделать его более стабильным и менее подверженным взлому в дальнейшем при внесении изменений.
Кроме того, не позволяйте себе расстраиваться из-за медленного процесса написания тестов. Это в основном только в начале, пока вы не привыкнете к API, и вы не станете так же бегло владеть действительной логикой, которую тестируете. Я чувствую, что важно также упомянуть, что в этой статье был представлен обзор высокого уровня экосистемы тестирования в Drupal 8, а также были довольно простые тесты. Я рекомендую более подробно изучить тему в будущем.