Статьи

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

Независимо от того, с каким приложением вы работаете, тестирование — это важный и часто упускаемый из виду аспект, на который следует обратить внимание, которого он заслуживает. Сегодня мы обсудим это в контексте веб-фреймворка Laravel.

Фактически, Laravel уже поддерживает среду тестирования PHPUnit в самом ядре. PHPUnit является одной из самых популярных и общепринятых сред тестирования в сообществе PHP. Это позволяет создавать оба вида тестов — модульные и функциональные.

Мы начнем с базового введения в модульное и функциональное тестирование. В дальнейшем мы рассмотрим, как создавать модульные и функциональные тесты в Laravel. Я предполагаю, что вы знакомы с основами платформы PHPUnit, поскольку мы рассмотрим ее в контексте Laravel в этой статье.

Если вы уже знакомы с платформой PHPUnit, вы должны знать, что вы можете разделить тесты на две разновидности: модульные тесты и функциональные тесты.

В модульных тестах вы проверяете правильность данной функции или метода. Что еще более важно, вы тестируете один фрагмент логики вашего кода в данный момент времени.

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

Давайте кратко рассмотрим пример, который идеально подходит для модульного тестирования.

1
2
3
4
public function getNameAttribute($value)
{
    return ucfirst($value);
}

Как видите, метод выполняет одну и только одну вещь. Он использует функцию ucfirst для преобразования заголовка в заголовок, который начинается с заглавной буквы.

В то время как модульный тест используется для проверки правильности одной логической единицы кода, функциональный тест, с другой стороны, позволяет проверить правильность конкретного варианта использования. Более конкретно, он позволяет имитировать действия, которые пользователь выполняет в приложении, для запуска конкретного варианта использования.

Например, вы можете реализовать функциональный тестовый пример для некоторых функций входа в систему, который может включать следующие шаги.

  • Создайте запрос GET для доступа к странице входа.
  • Проверьте, находимся ли мы на странице входа.
  • Сгенерируйте запрос POST для публикации данных на странице входа.
  • Проверьте, был ли сеанс успешно создан.

Так вот как вы должны создать функциональный тестовый пример. В следующем разделе мы создадим примеры, демонстрирующие, как создавать модульные и функциональные тестовые примеры в Laravel.

Прежде чем мы начнем создавать реальные тесты, нам нужно настроить пару вещей, которые будут использоваться в наших тестах.

Для начала мы создадим модель Post и связанную с ней миграцию. Продолжайте и выполните следующую команду ремесленника, чтобы создать модель Post .

1
$php artisan make:model Post —migration

Приведенная выше команда должна также создать класс модели Post и связанную миграцию базы данных.

Класс модели Post должен выглядеть следующим образом:

01
02
03
04
05
06
07
08
09
10
<?php
// app/Post.php
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
    //
}

И файл миграции базы данных должен быть создан по адресу database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php .

Мы также хотим сохранить заголовок поста. Давайте пересмотрим код файла миграции базы данных Post чтобы он выглядел следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create(‘posts’, function (Blueprint $table) {
            $table->increments(‘id’);
            $table->string(‘name’);
            $table->timestamps();
        });
    }
 
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists(‘posts’);
    }
}

Как видите, мы добавили столбец $table->string('name') для хранения заголовка поста. Далее вам просто нужно запустить команду migrate, чтобы фактически создать эту таблицу в базе данных.

1
$php artisan migrate

Также давайте заменим модель Post следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?php
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
    /**
     * Get the post title.
     *
     * @param string $value
     * @return string
     */
    public function getNameAttribute($value)
    {
        return ucfirst($value);
    }
}

Мы только что добавили метод accessor , который изменяет заголовок поста, и это именно то, что мы будем тестировать в нашем модульном тесте. Вот и все, что касается модели Post .

Далее мы создадим файл контроллера в app/Http/Controllers/AccessorController.php . Это будет полезно для нас, когда мы создадим функциональный тестовый пример на более позднем этапе.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
// app/Http/Controllers/AccessorController.php
namespace App\Http\Controllers;
 
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
 
 
class AccessorController extends Controller
{
    public function index(Request $request)
    {
        // get the post-id from request params
        $post_id = $request->get(«id», 0);
         
        // load the requested post
        $post = Post::find($post_id);
         
        // check the name property
        return $post->name;
    }
}

В методе index мы извлекаем идентификатор поста из параметров запроса и пытаемся загрузить объект модели поста.

Давайте добавим связанный маршрут также в файл routes/web.php .

1
Route::get(‘accessor/index’, ‘AccessorController@index’);

И с этим на месте, вы можете запустить http://your-laravel-site.com/accessor/index URL, чтобы увидеть, работает ли он должным образом.

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

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

Выполните следующую команду, чтобы создать класс модульного теста AccessorTest . Важно отметить, что мы --unit ключевое слово --unit которое создает пример модульного теста, и оно будет помещено в каталог tests/Unit .

1
$php artisan make:test AccessorTest —unit

И это должно создать следующий класс в tests/Unit/AccessorTest.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<?php
// tests/Unit/AccessorTest.php
namespace Tests\Unit;
 
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
 
class AccessorTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

Давайте заменим его каким-то значимым кодом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
// tests/Unit/AccessorTest.php
namespace Tests\Unit;
 
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use App\Post;
 
class AccessorTest extends TestCase
{
    /**
     * Test accessor method
     *
     * @return void
     */
    public function testAccessorTest()
    {
        // load post manually first
        $db_post = DB::select(‘select * from posts where id = 1’);
        $db_post_title = ucfirst($db_post[0]->name);
         
        // load post using Eloquent
        $model_post = Post::find(1);
        $model_post_title = $model_post->name;
         
        $this->assertEquals($db_post_title, $model_post_title);
    }
}

Как видите, код точно такой же, как и в ядре PHP. Мы только что импортировали специфичные для Laravel зависимости, которые позволяют нам использовать необходимые API. В методе testAccessorTest мы должны проверить правильность метода getNameAttribute модели Post .

Для этого мы взяли пример сообщения из базы данных и подготовили ожидаемый вывод в переменной $db_post_title . Затем мы загружаем тот же пост, используя модель Eloquent, которая также выполняет метод getNameAttribute для подготовки заголовка поста. Наконец, мы используем метод assertEquals для сравнения обеих переменных, как обычно.

Так вот, как подготовить юнит-тесты в Laravel.

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

Выполните следующую команду, чтобы создать класс функционального теста AccessorTest . Поскольку мы не используем ключевое слово --unit , оно будет рассматриваться как функциональный тестовый пример и помещено в каталог tests/Feature .

1
$php artisan make:test AccessorTest

Он создаст следующий класс в tests/Feature/AccessorTest.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// tests/Feature/AccessorTest.php
namespace Tests\Feature;
 
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
 
class AccessorTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

Давайте заменим его следующим кодом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
// tests/Feature/AccessorTest.php
namespace Tests\Feature;
 
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
 
class AccessorTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        // load post manually first
        $db_post = DB::select(‘select * from lvl_posts where id = 1’);
        $db_post_title = ucfirst($db_post[0]->name);
 
        $response = $this->get(‘/accessor/index?id=1’);
 
        $response->assertStatus(200);
        $response->assertSeeText($db_post_title);
    }
}

Опять же, код должен выглядеть знакомым для тех, кто имеет предыдущий опыт функционального тестирования.

Во-первых, мы выбираем пример сообщения из базы данных и готовим ожидаемый вывод в переменной $db_post_title . После этого мы пытаемся смоделировать запрос GET /accessor/index?id=1 и получить ответ на этот запрос в переменной $response .

Затем мы попытались сопоставить код $response переменной $response с ожидаемым кодом ответа. В нашем случае это должно быть 200, поскольку мы должны получить действительный ответ на наш запрос GET. Кроме того, ответ должен содержать заголовок, который начинается с заглавной буквы, и это именно то, что мы пытаемся сопоставить, используя метод assertSeeText .

И это пример функционального теста. Теперь у нас есть все, с чем мы могли бы протестировать. Давайте продолжим и запустим следующую команду в корне вашего приложения, чтобы запустить все тесты.

1
$phpunit

Это должно запустить все тесты в вашем приложении. Вы должны увидеть стандартный вывод PHPUnit, который отображает состояние тестов и утверждений в вашем приложении.

И с этим мы в конце этой статьи.

Сегодня мы изучили детали тестирования в Laravel, который уже поддерживает PHPUnit в своем ядре. Статья началась с базового введения в модульное и функциональное тестирование, и по мере продвижения мы исследовали особенности тестирования в контексте Laravel.

В ходе этого процесса мы создали несколько примеров, демонстрирующих, как можно создавать модульные и функциональные тестовые примеры с помощью команды кустарного мастера.

Если вы только начинаете работать с Laravel или хотите расширить свои знания, сайт или приложение с помощью расширений, у нас есть множество вещей, которые вы можете изучить на Envato Market .

Не стесняйтесь выражать свои мысли, используя канал ниже!