Giới thiệu về Testing trong Laravel

Giới thiệu về Testing trong Laravel

Giới thiệu

1. Một số khái niệm cơ bản.

  1. Unit Test: Kiểm thử mức đơn vị. Trong Unit Test chúng ta sẽ kiểm thử các class, method, function, ... Mục tiêu của Unit Test là kiểm thử tính đúng đắn của mỗi đơn vị trong một dự án.
  2. PHP Unit: Là một unit testing framework dành cho ngôn ngữ lập trình PHP. Nó cung cấp cho người sử dụng các class, method nhằm giúp cho việc viết các đoạn mã kiểm thử trở nên nhanh chóng và tiện lợi. Trong Laravel, PHP Unit được tích hợp sắn trong Laravel
  3. Unit Testing/Feature Testing: Trong Laravel có hai thư mục là Unit Test và Feature Test, chúng đều có mục đích để thực hiện viết mã kiểm thử các function, method trong dự án của chúng ta. Unit Test cho phép chúng ta kiểm thử các class models, controllers, ... Mục tiêu của Unit Test là để kiểm thử tính đúng đắn của từng đơn vị trong mã nguồn. Feature Test cho phép chúng ta test các api, các kết quả trả về như Http Request, Json, ...cùng với đó là test chức năng, hiệu năng và khả năng chịu tải của ứng dụng.
  4. Assertion: Là câu lệnh nhằm mục đích xác nhận đúng tại một đoạn code hay một function. Hiểu theo cách ngắn gọn, Assertion sẽ là kết quả mà bạn muốn nó xảy ra. Ví dụ bạn muốn kết quả trả về là true, bạn gọi hàm assertTrue(). Và unit test được pass khi các hàm assert trả về true

Bắt đầu với PHP Unit trong Laravel

2. Cấu hình PHP Unit

Sau khi khởi tạo một Laravel Project sẽ xuất hiện file phpunit.xml để thực hiện cấu hình PHP Unit. Một file phpunit.xml sẽ có cấu trúc cơ bản như sau:

    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </coverage>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="your_database"/>
        <server name="DB_DATABASE" value="database_name"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>

Trong đó
color="true" làm cho kết quả test được bôi màu.
testsuites chứa các testsuite là các folder thực hiện kiểm thử.
thẻ server chứa các config database.

Để chạy một unit test, ta cần tạo một file .env.testing tương tự file .env. Đây được coi là một file .env để thực hiện chạy trên môi trường test.
Thực hiện cài đặt môi trường test bằng câu lệnh php artisan migrate --env=testing

3. Bắt đầu viết các Test Case

Để tạo một Feature mới chúng ta sử dụng câu lệnh:
php artisan make:test UserTest

Để tạo một Unit Test chúng ta sử dụng câu lệnh:
php artisan make:test UserTest --unit
Lưu ý: Các file trong thư mục app nên ánh xạ với các file trong thư mục test
Sau khi thực hiện một trong hai câu lệnh, Laravel sẽ generate cho chúng ta một file có nột dung như sau

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

Để tạo một function test cho một đối tượng bất kì thì tên các function test chúng ta đặt luôn bắt đầu với chữ test VD: testUserCanLogin

Tên phương thức test thường sẽ có 2 cách để đặt

  • test_user_login_passed()
  • testUserRegisterPassed()

Tiến hành viết TestCase đầu tiên

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserTest extends TestCase
{
    use RefreshDatabase;

    public function setUp()  : void
    {
        parent::setUp();
        // chạy passport trước khi thực hiện test tránh lỗi personal client not found
        $this->artisan('passport:install');
        // chuẩn bị sẵn data mẫu
        User::factory()->create();
    }
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function testApiClientLoginPassed()
    {
        $data = ['email' => $this->user->email, 'password' => '123'];
        $response = $this->json('POST', '/login', $data);
        $response->assertStatus(Response::HTTP_ACCEPTED)->assertJsonStructure(['data']);
    }
}

Ở đây có $data chứa các thông tin truyền vào một form bao gồm emailpassword. Function testApiClientLoginPassed thực hiện tương tự như người dùng đang nhập thông tin để thực hiện đang nhập. $response gọi đến phương thức POST với uri là /login với data truyền vào. Mong muốn sau khi thực hiện sẽ nhận được HTTP_REQUESTHTTP_ACCEPTED.

Chúng ta nên tạo với function được test một function test đúng và một function test sai (Tuy nhiên test vẫn phải pass)

Một class test tiêu chuẩn bao gồm 3 bước:

  • Chuẩn bị môi trường

  • Thực hiện test

  • Assertion

Ngoài ra chúng ta có thể sử dụng nhiều hàm assert khác nhau. Sau đây là một số hàm assert:

  • assertEquals($variable1, $variable2) : pass nếu hai giá trị $variable1$variable2 bằng nhau.
  • assertNotEquals($variable1, $variable2) : Ngược lại hàm assertEquals()
  • assertSame($variable1, $variable2) : pass nếu hai giá trị có cùng kiểu và giá trị, tương tự với so sánh ===
  • assertTrue($variable) : pass nếu giá trị của $variable là true.
  • assertJson($variable) : pass nếu giá trị trả về là Json và giống với $variable
  • assertStatus($status) : pass nếu giá trị trả về có Http Status giống với $status

Tham khảo thêm : https://phpunit.readthedocs.io/en/9.5/assertions.html

4. Tiến hành chạy TestCase

Chúng ta có hai cách để run test case:

  • php artisan test./vendor/bin/phpunit để thực hiện run tất cả các class test hiện có thể run.

  • ./vendor/bin/phpunit file để thực hiện run một class test chỉ định.

Kết quả nhận được

PHPUnit 9.5.6 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:04.727, Memory: 24.00 MB

OK (1 test, 1 assertion)

5. Lưu ý

  • PHPUnit không thể chạy các test với các phương thức protectedprivate , nên các bạn phải để modify của function test là public. Chúng ta cũng có thể dễ dàng tìm ra được file phpunit.xml, PHPUnit sẽ tự xác định vị trí cho tên file được đặt tên trong phpunit.xml hoặc phpunit.xml.dist ở trong thư mục thực thi hiện tại. Ở trong file này, chúng ta có thể cấu hình cụ thể sự thực thi cho test của mình.

  • Trong mỗi các file test chúng ta tạo ra đều use trait RefreshDatabase. Trait này nhằm mục đích remove tất cả các data chúng ta tạo trong quá trình run unit test.

  • Trong mỗi Class Test chúng ta có thể thêm function setUp() : void chứa data để chạy và function tearDown() : void để hủy các phần chúng ta đã tạo ở setUp

Kết luận

Chúng ta đã tìm hiểu tổng quan về PHP Unit trong Laravel, cách config, viết một kịch bản test và thực hiện run một kịch bản.
Vẫn còn rất nhiều thứ để học nhưng tổng quan với những hướng dẫn trên, chúng ta có thể tạo những kịch bản test đơn giản để tiến hành kiểm thử cho dự án của mình.

Tài liệu tham khảo