7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. PHP

Тестирование в Laravel: Модели

Scroll to top
Read Time: 11 mins

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Если вы надеетесь узнать, почему тесты полезны, это не статья для вас. В ходе этого урока я предполагаю, что вы уже понимаете преимущества и надеетесь узнать, как лучше писать и организовывать свои тесты в Laravel 4.

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


Настройка

База данных в памяти

Если вы не используете сырые запросы в своей базе данных, Laravel позволяет вашему приложению оставаться агностиком базы данных. При простом изменении драйвера ваше приложение теперь может работать с другими СУБД (MySQL, PostgreSQL, SQLite и т.д.). Среди стандартных опций SQLite предлагает своеобразную, но очень полезную функцию: базы данных в памяти.

С Sqlite мы можем установить подключение к базе данных :memory:, что значительно ускорит наши тесты так как база данных не будет располагаться на жестком диске. Кроме того, база данных никогда не будет заполнена данными, оставшимися от предыдущих тестов, потому что соединение :memory: всегда начинается с пустой базы данных.

Короче говоря: база данных в памяти позволяет быстро и чисто тестировать приложение.

В каталоге app/config/testing создайте новый файл с именем database.php и заполните его следующим содержимым:

Тот факт, что database.php помещен в каталог конфигурации testing, означает, что эти параметры будут использоваться только в тестовой среде (которую автоматически устанавливает Laravel). Таким образом, когда к вашему приложению обращаются нормально, база данных в памяти не будет использоваться.

Перед запуском тестов

Поскольку база данных в памяти всегда пуста при подключении, важно migrate базу данных перед каждым тестом. Для этого откройте app/tests/TestCase.php и добавьте следующий метод в конец класса:

ПРИМЕЧАНИЕ. Метод setUp() выполняется PHPUnit перед каждым тестом.

Этот метод подготовит базу данных и изменит статус класса Mailer Laravel на pretend. Таким образом, Mailer не будет отправлять какие-либо реальные сообщения при запуске тестов. Вместо этого он будет записывать «отправленные» сообщения.

Чтобы завершить app/tests/TestCase.php, вызовите метод prepareForTests() в методе setUp() PHPUnit, который будет выполняться перед каждым тестом.

Не забудьте вызвать parent::setUp(), поскольку мы переписываем метод родительского класса.

На этом этапе app/tests/TestCase.php должен выглядеть следующим образом. Помните, что createApplication создается автоматически Laravel. Вам не нужно беспокоиться об этом.

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


Тесты

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

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

Модель Post

Обратите внимание, что модель расширяет класс, Ardent, а не Eloquent. Ardent - это пакет, который упрощает проверку при сохранении модели (см. свойство $rules).

Затем у нас есть public static $factory массив, который использует пакет FactoryMuff, чтобы помочь при создании объекта для тестирования.

Как Ardentx, так и FactoryMuff доступны через Packagist и Composer.

В нашей модели Post мы имеем отношение к модели User, используя магический метод author.

Наконец, у нас есть простой метод, который возвращает дату, отформатированную как «day/month/year».

Тестирование Post

Чтобы все было организовано, я поместил класс с тестами модели Post в app/tests/models/PostTest.php. Мы пройдем все тесты, по одной секции за раз.

Мы расширяем класс TestCase, что является требованием для тестирования PHPUnit в Laravel. Кроме того, не забывайте о нашем методе prepareTests, который будет выполняться перед каждым тестом.

Этот тест является «необязательным». Мы проверяем, что отношение «Post принадлежит User». Цель здесь - в основном продемонстрировать функциональность FactoryMuff.

Когда класс Post имеет статический массив $factory, содержащий 'author_id' => 'factory|User' (обратите внимание на исходный код модели, показанный выше), FactoryMuff создает экземпляр нового User, который заполняет его атрибуты, сохраняет в базе данных и, наконец, возвращает его author_id атрибут в Post.

Чтобы это было возможно, модель User должна иметь массив $factory, описывающий его поля.

Обратите внимание, как вы можете получить доступ к отношениям User через $post->author. Например, мы можем получить доступ к $post->author->username или любому другому существующему пользовательскому атрибуту.

Пакет FactoryMuff позволяет быстро создавать последовательные объекты для целей тестирования, соблюдая и создавая любые необходимые отношения. В этом случае, когда мы создаем Post с FactoryMuff::create('Post'), User также будет подготовлен и доступен.

Чтобы закончить, мы определяем, следует ли строка, возвращаемая методом publishAt(),  формату «день/месяц/год». Для такой проверки мы используем регулярное выражение, если шаблон \d{2}\/\d{2}\/\d{4}("2 числа" + "bar" + "2 цифры" + "bar «+» 4 числа»).

В качестве альтернативы мы могли бы использовать assertRegExp PHPUnit.

На этом этапе файл app/tests/models/PostTest.php выглядит следующим образом:

PS: Я решил не писать названия тестов в CamelCase для удобства чтения. PSR-1 простите меня, но testRelationWithAuthor не так читается, как я бы предпочел лично. Конечно, вы можете использовать стиль, который вам больше всего нравится.

Модель Page

Нашей CMS нужна модель для представления статических страниц. Эта модель реализована следующим образом:

Мы можем заметить, что статический метод renderMenu() предоставляет ряд ссылок для всех существующих страниц. Это значение сохраняется в кеше под ключом  'pages_for_menu'. Таким образом, в будущем вызовы renderMenu() не будут нуждаться в реальной базе данных. Это может значительно улучшить производительность нашего приложения.

Однако, если Page сохранена или удалена (методы afterSave() и delete()), значение кеша будет очищено, в результате renderMenu() будет отражать новое состояние базы данных. Итак, если имя страницы изменено или если оно удалено, ключ «pages_for_menu» очищается из кеша. (Cache::forget( 'pages_for_menu');)

ПРИМЕЧАНИЕ. Метод afterSave() доступен через пакет Ardent. В противном случае было бы необходимо реализовать метод save() для очистки кеша и вызвать parent::save();

Тестирование Page

В: app/tests/models/PageTest.php, мы напишем следующие тесты:

Еще раз, у нас есть «необязательный» тест, подтверждающий отношения. Поскольку отношениями являются Illuminate\Database\Eloquent, которые уже охвачены собственными тестами Laravel, нам не нужно писать еще один тест, чтобы подтвердить, что этот код работает так, как ожидалось.

Это один из самых важных тестов для модели Page. Сначала в цикле for создаются четыре страницы. После этого результат вызова renderMenu() сохраняется в переменной $result. Эта переменная должна содержать строку HTML, содержащую ссылки на существующие страницы.

Цикл foreach проверяет, присутствует ли слаг (url) каждой страницы в $result. Этого достаточно, поскольку точный формат HTML не имеет отношения к нашим потребностям.

Наконец, мы определяем, хранит ли кэш какие-нибудь данные по ключу pages_for_menu. Другими словами, действительно ли вызов renderMenu() фактически сохранил некоторое значение в кеше?

Этот тест предназначен для проверки того, сохраняется ли при сохранении новой Page ключ кеша 'pages_for_menu'. FactoryMuff::create('Page'); в конечном итоге вызывает метод save(), поэтому для ключа должно быть достаточно pages_for_menu, которое должно быть очищено.

Как и в предыдущем тесте, это определяет, правильно ли освобождается ключ 'pages_for_menu' после удаления Page.

Ваш PageTest.php должен выглядеть так:

Модель User

В связи с ранее представленными моделями у нас теперь есть User. Вот код для этой модели:

Эта модель отсутствует в тестах.

Мы можем заметить, что, за исключением отношений (которые могут быть полезны для тестирования), здесь нет никакой реализации. Как насчет аутентификации? Ну, использование пакета Confide уже обеспечивает реализацию и тесты для этого.

Тесты для Zizaco\Confide\ConfideUser расположены в ConfideUserTest.php.

Перед написанием тестов важно определить обязанности класса. Тестирование опции «сброса пароля» User будет избыточным. Это связано с тем, что надлежащая ответственность за этот тест принадлежит Zizaco\Confide\ConfideUser; а не  User.

То же самое верно для тестов проверки данных. Поскольку пакет, Ardent, справляется с этой ответственностью, не имеет смысла снова тестировать эту функциональность.

Короче говоря: держите свои тесты в чистоте и организованности. Определите надлежащую ответственность каждого класса и проверяйте только то, что является его ответственностью.


Вывод

Running Tests

Использование базы данных в памяти - хорошая практика для быстрого выполнения тестов с базой данных. Благодаря помощи некоторых пакетов, таких как Ardent, FactoryMuff и Confide, вы можете минимизировать количество кода в своих моделях, сохраняя при этом тесты чистыми и объективными.

В продолжении этой статьи мы рассмотрим тестирование контроллера. Будьте на связи!

Все еще новичок в Laravel 4, давайте научим вас основам!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.