Блог

Unit-тесты и события моделей в Laravel 4

19 января 2015 Рубрики: Программирование.

Буквально на днях столкнулся с проблемой, когда события модели не вызываются в unit-тестах. Далее — простое решение с предысторией.

Спустя чуть менее, чем два года после первого релиза пакета ClosureTable по просьбе трудящихся я решил создать демо-репозиторий для демонстрации его использования и выбрал сущность «Страница» (Page) в качестве примера. Решил сделать всё более-менее по уму, создал репозиторий EloquentPageRepository, написал для него несколько тестов, но обнаружил, что сидер TestPagesSeeder не заполняет таблицу pages_closure необходимыми данными со связями между страницами.

Полчаса тупняка, и тут я вдруг вспомнил, что обновление таблицы со связями происходит по вызову соответствующих событий модели Page, которые она наследует от Entity. Гуглёж вывел меня на длинный тред на Гитхабе по поводу бага с событиями моделей в Laravel. В итоге решение подсказал пользователь @Flightfreak и заключается оно в следующем.

Решение

Мы берём и «перезагружаем» события модели перед каждым тестом.

ModelName::flushEventListeners();
ModelName::boot();

В общем случае их нужно добавить в класс TestCase в метод setUp, например. Мне же пришлось добавить эти строчки в сидер, поскольку в нем идет заполнение базы данных, но в класс TestCase (поставляется с Laravel) я их тоже прописал на всякий случай…

<?php

use Faker\Factory as F;
use Franzose\ClosureTable\Demo\Models\Page\EloquentPage;

class TestPagesSeeder extends Seeder {

    public function run()
    {
        EloquentPage::flushEventListeners();
        EloquentPage::boot();

        $faker = F::create();
        $pages = [];

        foreach(range(0, 2) as $idx)
        {
            $title = 'Title ' . $idx;
            $slug  = Str::slug($title);
            $data  = [
                'title'   => $title,
                'slug'    => $slug,
                'content' => $faker->text(),
                'meta_keywords'     => 'a, b, c, d',
                'meta_description'  => $faker->sentence()
            ];

            $pages[] = EloquentPage::create($data);
        }

        $pages[0]->addChild($pages[1]);
        $pages[1]->addChild($pages[2]);
    }
}