Работа с данными
Тесты не должны влиять друг на друга. Это общее правило. Когда тесты взаимодействуют с базой данных, они могут изменять данные в ней, что в конечном итоге приведет к несогласованности данных. Тест может попытаться вставить запись, которая уже была вставлена, или извлечь удаленную запись. Чтобы избежать сбоев тестов, база данных должна быть возвращена в исходное состояние перед каждым тестом. Codeception предоставляет различные методы и подходы для очистки данных.
В этом разделе обобщаются все замечания по очистке из предыдущих разделов и предлагаются лучшие стратегии выбора бэкендов хранения данных.
Когда мы решаем очистить базу данных, мы должны сделать эту очистку максимально быстрой. Тесты всегда должны выполняться быстро. Перестройка базы данных с нуля не является лучшим способом, но может быть единственным. В любом случае вы должны использовать отдельную тестовую базу данных для тестирования. Никогда не запускайте тесты на базах данных разработки или производства!
База данных (Db)
Codeception имеет модуль Db , который берет на себя большинство задач взаимодействия с базой данных.
modules:
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password: Модуль Db может очищать базу данных между тестами, загружая дамп базы данных. Это можно сделать, разобрав файл SQL и выполнив его команды с использованием текущего подключения.
modules:
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password:
dump: tests/_data/your-dump-name.sql
cleanup: true # reload dump between tests
populate: true # load dump before all tests В качестве альтернативы можно использовать внешний инструмент (например, mysql client или pg_restore). Этот подход быстрее и не будет генерировать ошибки при разборе при загрузке дампа. Используйте populator параметр конфигурации для указания команды. Для MySQL он может выглядеть так:
modules:
enabled:
- Db:
dsn: 'mysql:host=localhost;dbname=testdb'
user: 'root'
password: ''
cleanup: true # run populator before each test
populate: true # run populator before all test
populator: 'mysql -u $user $dbname < tests/_data/dump.sql' См. справочник по модулю Db для получения дополнительных примеров.
Чтобы убедиться, что дамп базы данных загружается перед всеми тестами, добавьте populate: true. Чтобы очистить текущую базу данных и перезагрузить дамп между тестами, используйте cleanup: true.
В приемочных тестах ваши тесты взаимодействуют с приложением через веб-сервер. Это означает, что тест и приложение работают с одной и той же базой данных. Вам необходимо указать те же учетные данные в модуле Db, что и ваше приложение использует, затем вы можете получить доступ к базе данных для утверждений (seeInDatabase действия) и для выполнения автоматических очисток.
Модуль Db предоставляет действия для создания и проверки данных в базе данных.
Если вы хотите создать специальную запись в базе данных для одного теста, вы можете использовать метод haveInDatabase модуля Db:
<?php
$I->haveInDatabase('posts', [
'title' => 'Top 10 Testing Frameworks',
'body' => '1. Codeception'
]);
$I->amOnPage('/posts');
$I->see('Top 10 Testing Frameworks'); haveInDatabase вставляет строку со значениями в базу данных. Все добавленные записи будут удалены в конце теста.
Если вы хотите проверить, что запись в таблице была создана, используйте метод seeInDatabase:
<?php
$I->amOnPage('/posts/1');
$I->fillField('comment', 'This is nice!');
$I->click('Submit');
$I->seeInDatabase('comments', ['body' => 'This is nice!']); См. справочник по модулю для других методов, которые вы можете использовать для тестирования базы данных.
Также есть модули для MongoDb, Redis и Memcache, которые ведут себя аналогично.
Последовательность
Если очистка базы данных занимает слишком много времени, вы можете следовать другой стратегии: создавать новые данные для каждого теста. Таким образом, единственной проблемой, с которой вы можете столкнуться, является дублирование записей данных. Sequence был создан для решения этой проблемы. Он предоставляет функцию sq(), которая генерирует уникальные суффиксы для создания данных в тестах.
Модули ORM
Ваше приложение, скорее всего, использует объектно-реляционное отображение (ORM) для работы с базой данных. В этом случае Codeception позволяет использовать методы ORM для работы с базой данных вместо прямого доступа к базе данных. Таким образом, вы можете работать с моделями и сущностями домена, а не с таблицами и строками.
Используя ORM в функциональных и интеграционных тестах, вы также можете улучшить производительность своих тестов. Вместо очистки базы данных после каждого теста, модуль ORM заворачивает все действия базы данных в транзакции и откатывает их в конце. Таким образом, никакие фактические данные не будут записаны в базу данных. Эта стратегия очистки включена по умолчанию, вы можете отключить ее, установив cleanup: false в конфигурации любого модуля ORM.
ActiveRecord
Популярные фреймворки, такие как Laravel, Yii и Phalcon, по умолчанию включают уровень данных ActiveRecord. Из-за этой тесной интеграции вам просто нужно включить модуль фреймворка и использовать его конфигурацию для доступа к базе данных.
Соответствующие модули фреймворка предоставляют аналогичные методы для доступа к ORM:
haveRecordseeRecorddontSeeRecordgrabRecord
Они позволяют создавать и проверять данные по имени модели и именам полей в модели. Вот пример в Laravel:
<?php
// create record and get its id
$id = $I->haveRecord('posts', ['body' => 'My first blogpost', 'user_id' => 1]);
$I->amOnPage('/posts/'.$id);
$I->see('My first blogpost', 'article');
// check record exists
$I->seeRecord('posts', ['id' => $id]);
$I->click('Delete');
// record was deleted
$I->dontSeeRecord('posts', ['id' => $id]); Модуль Laravel5 предоставляет метод have, который использует метод factory для генерации моделей с фейковыми данными.
Если вы хотите использовать ORM только для интеграционного тестирования, вы должны включить модуль фреймворка, включив только часть ORM:
modules:
enabled:
- Laravel5:
- part: ORM modules:
enabled:
- Yii2:
- part: ORM Таким образом, никакие веб-действия не будут добавлены к объекту $I.
Если вы хотите использовать ORM для работы с данными внутри приемочных тестов, вы также должны включить только часть ORM модуля. Обратите внимание, что внутри приемочных тестов веб-приложения работают внутри веб-сервера, поэтому любые тестовые данные не могут быть очищены путем отката транзакций. Вам необходимо отключить очистку и использовать модуль Db для очистки базы данных между тестами. Вот пример конфигурации:
modules:
enabled:
- WebDriver:
url: http://localhost
browser: firefox
- Laravel5:
cleanup: false
- Db Doctrine
Doctrine также является популярным ORM, в отличие от некоторых других, он реализует шаблон DataMapper и не связан ни с одним фреймворком. Модуль Doctrine2 требует экземпляра EntityManager для работы. Его можно получить из фреймворка Symfony или Zend Framework (настроенного с Doctrine):
modules:
enabled:
- Symfony
- Doctrine2:
depends: Symfony modules:
enabled:
- ZF2
- Doctrine2:
depends: ZF2 Если фреймворк не используется с Doctrine, вы должны предоставить опцию connection_callback со допустимым обратным вызовом функции, которая возвращает экземпляр EntityManager.
Doctrine2 также предоставляет методы для создания и проверки данных:
haveInRepositorygrabFromRepositorygrabEntitiesFromRepositoryseeInRepositorydontSeeInRepository
DataFactory
Подготовка данных для тестирования — очень творческая, хотя и скучная задача. Если вы создаете запись, вам необходимо заполнить все поля модели. Гораздо проще использовать Faker для этой задачи, который более эффективен для настройки правил генерации данных для моделей. Такой набор правил называется фабриками и предоставляется модулем DataFactory.
После настройки он может легко создавать записи:
<?php
// creates a new user
$user_id = $I->have('App\Model\User');
// creates 3 posts
$I->haveMultiple('App\Model\Post', 3); Созданные записи будут удалены в конце теста. Модуль DataFactory работает только с ORM, поэтому ему требуется один из модулей ORM для включения:
modules:
enabled:
- Yii2:
configFile: path/to/config.php
- DataFactory:
depends: Yii2 modules:
enabled:
- Symfony
- Doctrine2:
depends: Symfony
- DataFactory:
depends: Doctrine2 DataFactory предоставляет мощное решение для управления данными в интеграционных/функциональных/приемочных тестах. Прочитайте полный справочник, чтобы узнать, как настроить этот модуль.
Тестирование динамических данных со снимками
Что, если вы имеете дело с данными, которыми вы не владеете? Например, вид страницы зависит от количества категорий в базе данных, а категории устанавливаются пользователем-администратором. Как вы будете тестировать, что страница по-прежнему валидна?
Есть способ протестировать это тоже. Codeception позволяет вам сделать снимок данных при первом запуске и сравнить его с последующими запусками. Этот принцип настолько общий, что он может использоваться для тестирования API, элементов на веб-странице и т. д.
Давайте проверим, что список категорий на странице такой же, как и раньше.
Создайте класс снимка:
vendor/bin/codecept g:snapshot Categories
Внедрите класс актора через конструктор и реализуйте метод fetchData, который должен вернуть набор данных из теста.
<?php
namespace Snapshot;
class Categories extends \Codeception\Snapshot
{
/** @var \AcceptanceTester */
protected $i;
public function __construct(\AcceptanceTester $I)
{
$this->i = $I;
}
protected function fetchData()
{
// fetch texts from all 'a.category' elements on a page
return $this->i->grabMultiple('a.category');
}
} Внутри теста вы можете внедрить класс снимка и вызвать метод assert на нём:
<?php
public function testCategoriesAreTheSame(\AcceptanceTester $I, \Snapshot\Categories $snapshot)
{
$I->amOnPage('/categories');
// if previously saved array of users does not match current set, test will fail
// to update data in snapshot run test with --debug flag
$snapshot->assert();
} При первом запуске данные будут получены через метод fetchData и сохранены в директорию tests/_data в формате json. При последующих запусках полученные данные будут сравнены с ранее сохранённым снимком.
Чтобы обновить снимок с новыми данными, запустите тесты в режиме
--debug.
По умолчанию Snapshot использует assertEquals утверждение, но это можно настроить, переопределив метод assertData.
Вывод при ошибочном утверждении
Утверждение, выполняемое assertData, не будет отображать типичный вывод diff от assertEquals или любого настроенного утверждения об ошибке. Чтобы отобразить diff при выполнении тестов, вы можете вызвать метод снимка shouldShowDiffOnFail:
<?php
public function testCategoriesAreTheSame(\AcceptanceTester $I, \Snapshot\Categories $snapshot)
{
$I->amOnPage('/categories');
// I want to see the diff in case the snapshot data changes
$snapshot->shouldShowDiffOnFail();
$snapshot->assert();
} Если это необходимо, вывод diff также можно опустить, вызвав shouldShowDiffOnFail(false).
Работа с различными форматами данных
По умолчанию все файлы снимков хранятся в формате json, поэтому, если вам нужно работать с различными форматами, ни вывод diff, ни данные файла снимка не будут полезны. Чтобы это исправить, вы можете вызвать метод снимка shouldSaveAsJson(false) и установить расширение файла, вызвав setSnapshotFileExtension():
<?php
public function testCategoriesAreTheSame(\AcceptanceTester $I, \Snapshot\Categories $snapshot)
{
// I fetch an HTML page
$I->amOnPage('/categories.html');
// I want to see the diff in case the snapshot data changes
$snapshot->shouldSaveAsJson(false);
$snapshot->setSnapshotFileExtension('html');
$snapshot->assert();
} Файл снимка будет сохранён без его кодирования в формате json и с расширением .html.
Обратите внимание, что этот параметр не произведёт никаких изменений в данных, возвращаемых
fetchData, и сохранит их в исходном виде.
Заключение
Codeception также помогает разработчику при работе с данными. Инструменты для заполнения и очистки базы данных объединены в модуле Db. Если вы используете ORM, вы можете использовать один из предоставленных модулей фреймворка для работы с базой данных через слой абстракции данных и использовать модуль DataFactory для лёгкого создания новых записей.
- Следующая глава: Тестирование API >
- Предыдущая глава: < Настройка
© 2011 Michael Bodnarchuk and contributors
Licensed under the MIT License.
https://codeception.com/docs/09-Data