Các công cụ hữu ích cho debug code và kiểm thử trong Laravel

7th Jan 2023
Request: Chứa thông tin về yêu cầu như mã trạng thái (200, 301, 302, 404...), request header, response header và các giá trị trong session.
Table of contents

Có rất nhiều các tính năng thuần túy của Laravel hoặc các công cụ được cung cấp bởi bên thứ ba làm tăng hiệu quả viết mã nguồn bằng cách giảm thời gian và nỗ lực trong việc xác định và giải quyết các lỗi trong lập trình. Trong bài viết này chúng ta chỉ tập trung vào việc phát triển và debug trong Laravel chứ không nói đến việc debug cho PHP nói chung bởi có rất nhiều các công cụ cho PHP như FirePHP, Xdebug... rất nổi tiếng nhưng không phù hợp trong trường hợp cụ thể sử dụng framework Laravel.

Sử dụng dd() function

Để sử dụng được function này, phải bật tùy chọn debug lên, function dd() hiển thị thông tin về đối tượng được đưa vào

dd($value);
// Hoặc in ra thông tin nhiều đối tượng
dd($value1, $value2, $value3);

Ví dụ, chúng ta in ra một mảng như sau:

public function test(){
    $items = array(
        'items' => ['Laravel', 'Symfony', 'PHPCake', 'Zend framework']
    );
    dd($items);

    return view('welcome');
}

Kết quả khi chạy qua đoạn mã này như sau: 

Chú ý, hàm dd() sẽ hiển thị thông tin đối tượng được đưa vào

Chú ý, hàm dd() sẽ hiển thị thông tin đối tượng được đưa vào và dừng luôn chương trình tại điểm đặt hàm dd(). Nếu bạn muốn vừa hiển thị thông tin nhưng vẫn cho chương trình tiếp tục đến khi kết thúc thì sử dụng hàm dump().

dump($value);

Sử dụng Laravel logger

Hàm dd() có thể sử dụng để debug nhanh một đối tượng, tuy nhiên nếu bạn muốn kiểm tra nhiều cấu trúc dữ liệu một lúc và không muốn dừng chương trình khi debug. Laravel cung cấp một ứng dụng ghi log mặc định, toàn bộ lỗi phát sinh sẽ được ghi nhận vào file storage/logs/laravel.log. File log này được quản lý bởi Monolog, module này cho phép bạn ghi rất nhiều thông tin dạng mảng vào file log, cung cấp log ở các mức độ khác nhau, thậm chí gửi dữ liệu log sang công cụ debug Firebug thông qua FirePHP hoặc gửi dữ liệu log sang Chrome console thông qua Chrome Logger hoặc thậm chí gửi log qua email qua HipChat hoặc Slack. Tạo một message log rất đơn giản bằng cách chèn vào các hàm ghi log vào những đoạn bạn cần ghi log dữ liệu để debug ứng dụng.

public function test(){
    $items = array(
        'items' => ['Laravel', 'Symfony', 'PHPCake', 'Zend framework']
    );
    \Log::debug($items);

    return view('welcome');
}

Khi ứng dụng chạy qua đoạn mã ghi log này, nó sẽ ghi dữ liệu vào storage/logs/laravel.log thông tin như sau:

[2017-03-20 08:51:56] local.DEBUG: array (
 0 => 'Laravel',
 1 => 'Symfony',
 2 => 'PHPCake',
 3 => 'Zend framework',
)

Debug message có nhiều cấp độ khác nhau như chỉ ghi log thông tin, ghi log cảnh báo, ghi log lỗi, ghi log lỗi cực nghiêm trọng:

\Log::info('Ghi log thông tin.');
\Log::warning('Ghi log cảnh báo, có khả năng gây lỗi.');
\Log::error('Ghi log các trường hợp lỗi.');
\Log::critical('Ghi log lỗi nghiêm trọng');

Khi sử dụng Logger của Laravel, ứng dụng vẫn chạy bình thường, chúng ta có thể ghi vào log các đối tượng muốn debug tại các thời điểm chạy ứng dụng khác nhau, đặc biệt với các ứng dụng liên quan đến giao dịch chúng ta có thể ghi log dạng thông tin để đối chiếu dữ liệu trong CSDL.

Tích hợp Laravel Logger với FirePHP:

Khi debug chúng ta thường cần thông tin một cách nhanh chóng, việc ghi log vào file khiến chúng ta phải mất thêm nhiều thao tác như mở file, kiểm tra những đoạn log mới được ghi vào file (có thể sử dụng lệnh tail -f trong Linux để xem những thay đổi của log file). Tích hợp Laravel Logger với một công cụ log hiển thị trực quan giúp chúng ta kiểm tra nhanh chóng thông tin các đối tượng liên quan trong đoạn mã. FirePHP cho phép bạn truyền message log đến Firebug và bạn có thể xem được message log này ngay trên trình duyệt. Để thực hiện bạn cần cài đặt các add-on Firebug và FirePHP cho trình duyệt Firefox, sau đó khởi động lại trình duyệt và chúng ta đã có thể gửi message log trực tiếp đến trình duyệt:

$monolog = \Log::getMonolog();
$items = array(
    'items' => ['Laravel', 'Symfony', 'PHPCake', 'Zend framework']
);
$monolog->pushHandler(new \Monolog\Handler\FirePHPHandler());
$monolog->addInfo('Log Message', array('items' => $items));

Khi thực thi ứng dụng chạy qua đoạn mã này, chúng ta sẽ thấy mảng items xuất hiện trong Firebug console trên trình duyệt như hình dưới đây

Chú ý, hàm dd() sẽ hiển thị thông tin đối tượng được đưa vào

Tích hợp Laravel Logger với Chrome Logger

Tiếp theo, chúng ta sẽ thực hiện tích hợp Laravel Logger (Monolog) với Chrome console và Chrome Logger. Cài đặt Chrome Logger cho trình duyệt Chrome, khởi động lại trình duyệt. Chúng ta test thử việc truyền message log từ ứng dụng ra Chrome Logger và hiển thị trên console.

        $monolog = \Log::getMonolog();
        $items = array(
            'items' => ['Laravel', 'Symfony', 'PHPCake', 'Zend framework']
        );

        $monolog->pushHandler($chromeHandler = new \Monolog\Handler\ChromePHPHandler());
        $chromeHandler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter());
        $monolog->addInfo('Log Message', array('items' => $items));

Khi bạn thực hiện chạy một đường dẫn có thực thi đoạn mã trên, trong console sẽ xuất hiện message log như hình dưới

Chú ý, hàm dd() sẽ hiển thị thông tin đối tượng được đưa vào

Debug trong Laravel sử dụng Tinker console

Trong quá trình phát triển thường chúng ta muốn kiểm thử một đoạn mã, nếu đưa đoạn mã này để chạy thực tế sẽ mất nhiều thời gian, thay vào đó bạn có thể sử dụng Tinker console là một ứng dụng dòng lệnh cho phép bạn thực thi từng dòng lệnh. Mở Tinker bằng cách thực thi lệnh tại thư mục gốc của ứng dụng:

c:\xampp\htdocs\laravel-test>php artisan tinker --env=local
Psy Shell v0.8.2 (PHP 5.6.20 ΓÇö cli) by Justin Hileman
New version is available (current: v0.8.2, latest: v0.8.3)
>>>

Tinker sử dụng PsySH, một debug tool dòng lệnh theo thời gian thực, có thể tương tác và là REPL với ngôn ngữ PHP. Chúng ta bắt đầu với Tinker:

>>> $items = ['Laravel', 'Symfony', 'PHPCake', 'Zend framework'];
=> [
     "Laravel",
     "Symfony",
     "PHPCake",
     "Zend framework",
   ]

Trong tinker console chúng ta có thể thực hiện các lệnh của PHP, trong ví dụ tiếp theo đây chúng ta thử sử dụng lệnh sort() để sắp xếp mảng ở phần trên:

>>> $number_arr = [1, 3, 5, 2, 9, 7];
=> [
     1,
     3,
     5,
     2,
     9,
     7,
   ]
>>> var_dump($number_arr);
array(6) {
  [0]=>
  int(1)
  [1]=>
  int(3)
  [2]=>
  int(5)
  [3]=>
  int(2)
  [4]=>
  int(9)
  [5]=>
  int(7)
}
=> null
>>> sort($number_arr):
=> true
>>> $number_arr
=> [
     1,
     2,
     3,
     5,
     7,
     9,
   ]
>>>

Như vậy chúng ta có thể kiểm nghiệm các đoạn mã từng lệnh một. Khi kiểm tra mã xong, thực hiện thoát khỏi Tinker.

>>> exit
Exit:  Goodbye.

Laravel Debugbar công cụ debug chuyên nghiệp

Công cụ debug này cho phép bạn kiểm soát rất nhiều thông tin, sự kiện xảy ra khi một ứng dụng web chạy, nó được tích hợp trực tiếp vào dự án Laravel của bạn thông qua gói thư viện barryvdh/laravel-debugbar. Trước tiên chúng ta cài đặt gói này vào dự án bằng lệnh composer require (Xem Composer là gì để biết cách sử dụng công cụ này):

composer require barryvdh/laravel-debugbar
Using version ~2.0 for barryvdh/laravel-debugbar
./composer.json has been updated
...
Writing lock file
Generating autoload files

Tiếp theo chúng ta thêm provider cũng như alias để sử dụng sau này trong các đoạn mã sử dụng đến Laravel-debugbar vào file config/app.php:

// Thêm vào phần provider
'providers' => [
...
'Barryvdh\Debugbar\ServiceProvider'
],
// Thêm vào phần alias
'aliases' => [
...
'Debugbar' => 'Barryvdh\Debugbar\Facade'
]

Lưu thay đổi trên file config/app.php và cài đặt cấu hình gói vào config:

php artisan vendor:publish

Khi đó, trong thư mục config sẽ xuất hiện thêm file debugbar.php, Tải lại trang bất kỳ trong dự án, bạn sẽ thấy xuất hiện thanh Debugbar ở dưới đáy màn hình. Thanh này tương tự giống như Firebug, chứa nhiều các tab, khi click vào từng tab, thông tin liên quan sẽ hiển thị ở dưới:

  • Message: Tab này hiển thị các message log được log từ đoạn mã nào đó bạn muốn debug, sử dụng \Debugbar::error('message');.
  • Timeline: Thể hiện từng mốc thời gian yêu cầu tải trang đưa ra.
  • Exception: Hiển thị toàn bộ exception phát sinh trong yêu cầu hiện tại.
  • Views: hiển thị thông tin về view được sử dụng để tạo ra trang hiện tại.
  • Route: tab này hiển thị thông tin và các route yêu cầu, bao gồm cả các controller và action liên quan.
  • Queries: hiển thị các truy vấn SQL được thực thi khi xử lý yêu cầu.
  • Mails: hiển thị thông tin khi có bất kỳ email nào được gửi đi trong yêu cầu.
    • Request: Chứa thông tin về yêu cầu như mã trạng thái (200, 301, 302, 404...), request header, response header và các giá trị trong session.

Kiểm thử ứng dụng Laravel với PHPUnit

Kiểm thử ứng dụng tự động là một khâu quan trọng trong quy trình sản xuất phần mềm, đặc biệt với ứng dụng web khi mà môi trường chạy ứng dụng rất đa dạng với các loại trình duyệt khác nhau, phiên bản khác nhau... Ngay cả một dự án nhỏ, việc kiểm thử ứng dụng là không nên bỏ qua. Rất may mắn khi các nhà phát triển framework Laravel đã rất quan tâm đến việc kiểm thử ứng dụng và đã mặc định cài đặt gói PHPUnit cho các dự án Laravel, bạn có thể kiểm tra trong file composer.json ở thư mục gốc dự án:

    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~4.0",
        **"phpspec/phpspec": "~2.1",**
        "symfony/dom-crawler": "3.1.*",
        "symfony/css-selector": "3.1.*"
    },

PHPUnit là một công cụ dòng lệnh được cài đặt thông qua file composer.json ở trên và có thể tìm thấy file chạy trong vendor/bin (đây là một file batch để thực thi một file thuần php).

c:\xampp\htdocs\laravel-test\vendor\bin>phpunit --version
PHPUnit 5.7.16 by Sebastian Bergmann and contributors.

Trong thư mục tests của dự án Laravel chúng ta có thể thấy một file là ExampleTest.php, file này chứa một kịch bản kiểm thử đơn giản: truy cập trang chủ dự án và xác định xem có phải mã trạng thái 200 được trả về hay không?

<?php

use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $this->visit('/')
             ->see('Laravel 5');
    }
}

Để chạy kịch bản kiểm thử này chúng ta đơn giản là thực hiện câu lệnh:

vendor/bin/phpunit
PHPUnit 4.7.2 by Sebastian Bergmann and contributors.

Time: 615 ms, Memory: 12.00Mb

OK (1 test, 2 assertions)

Bây giờ chúng ta kiểm thử trường hợp trang chủ dự án không chạy xem thế nào, mở file routes/web.php và comment đoạn route trang chủ:

//Route::get('/', function(){
//        return view('welcome');
//});

Và chạy lại PHPUnit chúng ta sẽ thấy xuất hiện thông tin như sau:

vendor/bin/phpunit
PHPUnit 4.7.2 by Sebastian Bergmann and contributors.

F

Time: 403 ms, Memory: 11.75Mb

There was 1 failure:

1) ExampleTest::testBasicExample
A request to [http://localhost] failed. Received status code [404].

Chúng ta thấy kết quả kiểm thử, yêu cầu đến trang chủ lỗi với mã lỗi là 404 không tìm thấy trang yêu cầu.

Kết luận

Qua bài viết này chúng ta thấy có rất nhiều cách thức từ đơn giản đến phức tạp sử dụng để debug một dự án chạy framework Laravel, qua đó giúp chúng ta phát triển ứng dụng web nhanh chóng và giảm thiểu thời gian phát hiện và sửa chữa các lỗi xảy ra. Tuy rằng các công cụ debug trong Laravel nói riêng và PHP nói chung không sánh ngang được với công cụ debug trong Visual Studio của Microsoft cho các ngôn ngữ .NET nhưng từng này cũng đủ cho bạn phát triển những dự án lớn. Còn rất nhiều cách thức debug chuyên sâu hơn nữa cho Laravel nhưng trong khuôn khổ bài viết này chúng tôi tạm dừng tại đây và hẹn gặp lại bạn trong những bài viết khác.

Bạn thấy bài viết này như thế nào?
1 reaction

Add new comment

Image CAPTCHA
Enter the characters shown in the image.

Related Articles

Mỗi kết nối cơ sở dữ liệu được định nghĩa trong một mảng, với tên kết nối là khóa của mảng

Eager Loading là một kỹ thuật tối ưu hóa truy vấn cơ sở dữ liệu trong Laravel, giúp tăng tốc độ truy vấn và giảm số lượng truy vấn cần thiết để lấy dữ liệu liên quan đến một bản ghi.

Để sử dụng Eager Loading với điều kiện trong Laravel, bạn có thể sử dụng phương thức whereHas hoặc orWhereHas trong Eloquent Builder.

E hiểu đơn giản vầy nha. auth() hay Auth trong laravel là những function global hay class, nó cũng chỉ là 1 thôi

Xin chào các bạn, tuần này mình sẽ viết một bài về cách xử lý Real Time(thời gian thực) với Laravel và Pusher