Тестирование моделей

Laravel Test Driven Development

В этом уроке мы научимся тестировать Модели в Laravel через технику «Разработка через тестирование» (Test Driven Development). Для этого мы создадим новый проект, который имеет модель Article с полями title, content и views .

Создаём новый проект:

laravel new blog

или так:

composer create-project --prefer-dist laravel/laravel blog

Настройка модели Article и таблицы базы данных

Создаём модель Article с миграцией:

php artisan make:model Article -m

Сгенерированный файл для модели находится в app/Article.php.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    //
}

В таблице статей должны быть поля title, content и views, поэтому мы добавим их в файл миграции находящийся в database/migrations/create_articles_table.php.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();

            $table->string('title');
            $table->text('content');
            $table->integer('views')->default(0);
        });
    }

    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

Запустим команду для создания таблицы

php artisan migrate

Пишем тесты для модели Article

Наша модель Article готова к тестированию. Мы будем писать интеграционные тесты, но перед этим давайте создадим фабрику.

php artisan make:factory ArticleFactory --model=Article

Сгенерированная фабрика появится в database/factories/ArticleFactory.php.

use Faker\Generator as Faker;

$factory->define(App\Article::class, function (Faker $faker) {
    return [
        'title' => $faker->name,
        'content' => $faker->sentence
    ];
});

Создайте файл tests/Integration/models/ArticleTest.php для интеграционного теста.

Его содержимое должно быть таким:

namespace Tests\Integration\models;

use App\Article;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ArticleTest extends TestCase
{
    /** @test */
    function it_fetches_most_viewed_articles()
    {
        factory(Article::class, 5)->create();
        factory(Article::class)->create(['views' => 100]);
        $mostViewed = factory(Article::class)->create(['views' => 200]);

        $articles = Article::mostViewed();

        $this->assertEquals($mostViewed->id, $articles->first()->id);
    }
}

Этот тест создает 5 статей с нулевым количеством просмотров, одну статью со 100 просмотрами и самую просматриваемую статью с 200 просмотрами. Тест проверяет, возвращает ли метод Article::mostViewed() тот же идентификатор, что и самая просматриваемая статья.

Запуск теста и корректировка модели на основе результатов

Запускаем тестирование через phpunit:

php artisan test tests/Integration/models/ArticleTest.php

Тест не пройдет, потому что метод Article::mostViewed() еще не реализован. Давайте напишем его в файле модели Article:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public function scopeMostViewed($query)
    {
        $query->orderBy('views','desc');
    }
}

Если вы снова запустите тестирование, то тест всё равно не пройдет, потому что сохранились данные прошлого теста. Нам нужно, чтобы база данных обновлялась для каждого тестирования. Это можно сделать применив трейт RefreshDatabase. Теперь ArticleTest должен выглядеть так:

namespace Tests\Integration;

use App\Article;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ArticleTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    function it_fetches_most_viewed_articles()
    {
        factory(Article::class, 5)->create();
        factory(Article::class)->create(['views' => 100]);
        $mostViewed = factory(Article::class)->create(['views' => 200]);

        $articles = Article::mostViewed();

        $this->assertEquals($mostViewed->id, $articles->first()->id);
    }
}

Теперь тест выполняется успешно!

Автор: Emmanuel Corrales
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.