Giới thiệu thư viện Faker trong laravel

Testing là một công việc lặp đi lặp lại trong quá trình phát triển ứng dụng mà chúng ta thực hiện để đảm bảo chất lượng cho những dòng code.

Phần lớn điều này đòi hỏi phải viết các test case và tiến hành kiểm tra từng đơn vị của ứng dụng với việc sử dụng dữ liệu test ngẫu nhiên.

Dữ liệu thực tế cho ứng dụng của chúng ta đến khi chúng ta chính thức phát hành sản phẩm. Tuy nhiên, trong toàn bộ quá trình phát triển, chúng ta cần có bộ dữ liệu fake tương tự như dữ liệu thật cho quá trình test. Để đáp ứng cho yêu cầu cấp thiết trên, bộ thư viện mã nguồn mở Faker cho chúng ta khả năng tạo ra các bộ dữ liệu khác nhau phù hợp với một loạt yêu cầu về dữ liệu.

Dưới đây tôi sẽ tập trung trình bày cách sử dụng thư viện Faker để tạo ra một bộ dữ liệu random.

Trước tiên, Faker có thể sinh ra bộ dữ liệu phù hợp với các kiểu sau:

  • Kiểu số
  • Kiểu văn bản
  • Bộ dữ liệu cho một người. Ví dụ như tên, tuổi, giới tính, etc..
  • Địa chỉ
  • Số điện thoại
  • Công ty
  • Ký tự
  • Ngày tháng
  • Internet, ví dụ như domains, URLs, etc..
  • Màu sắc
  • File
  • Images
  • ...

Chúng ta sẽ tiến hành nghiên cứu một ví dụ sử dụng Faker căn bản nhất.

** Bước 1: Tạo 1 file migrate **

Trên cửa sổ terminal, để thư mục root là thư mục dự án của bạn, tiến hành chạy lệnh:

php artisan make:migration create_users_table

đối với laravel 5.x. Sau khi hoàn tất câu lệnh trên, các bạn vào thư mục

database/migrations/

mở file 2014_10_12_000000_create_users_table.php. Lưu ý, giá trị thời gian khi bạn chạy câu lệnh khởi tạo migration sẽ khác với giá trị thời gian file ví dụ của tôi. Đây là giá trị thời gian trên server khi các bạn chạy câu lệnh.

Thay đổi code trong file trên như sau:

<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('contact_number');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
    }
}

Nếu các bạn thấy những dòng code trên khá lạ lẫm. Các bạn hãy tìm đọc hướng dẫn về Migrations.

Sau khi hoàn tất và save lại file. Trên Terminal tiến hành chạy lệnh

php artisan migrate

Bạn sẽ nhận được thông báo sau:

Migrated: 014_10_12_000000_create_users_table

Chạy câu lệnh sau để tạo seeder cho bảng vừa migrated

php artisan make:seeder UsersTableSeeder

Khi có thông báo này hiện ra là quá trình tạo seeder đã hoàn tất.

Seeder created successfully

Mở file ** /database/seeds/UsersTableSeeder.php **

Thay đổi nội dung file như sau:

<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = Faker\Factory::create();

        $limit = 10;

        for ($i = 0; $i < $limit; $i++) {
            DB::table('users')->insert([
                'name' => $faker->name,
                'email' => $faker->unique()->email,
                'contact_number' => $faker->phoneNumber,
            ]);
        }
    }
}

Với đoạn code trên, chúng ta sẽ có thông tin của 10 người dùng, với các trường là tên, địa chỉ email và số điện thoại.

Tiếp theo, mở file database/seeds/DatabaseSeeder.php và thêm dòng thay đổi như sau:

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Model::unguard();
        $this->call(UsersTableSeeder::class);
        Model::reguard();
    }
}

Save file và chạy lệnh

php artisan db:seed --class=UsersTableSeeder

Nếu không có bất kỳ thông báo lỗi nào hiện lên, tức là quá trịnh chạy seeder đã hoàn tất. Các bạn có thể tiến hành truy cập vào database để kiểm tra lại dữ liệu.

Đây là một kết quả khi tiến hành thao tác theo các bước trên:

1.png

Với Laravel, thay vì gọi lệnh insert và faker trong file Seeder thì việc chúng ta định nghĩa trước cấu trúc dữ liệu cần để insert vào database sẽ giúp cho chúng ta tối ưu được code và tiện lợi cho quá trình chỉnh sửa. Để làm được điều này, Laravel cung cấp cho chúng ta Model Factories.

** Tạo Model Factories **

Hãy mở file database/factories/ModelFactory.php và bạn sẽ thấy định nghĩa mặc định cho factory như sau:

$factory->define(App\Model\User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'password' => bcrypt(str_random(10)),
        'remember_token' => str_random(10),
    ];
});

Từ định nghĩa mẫu trên, áp dụng cho ví dụ bảng users của chúng ta ở ví dụ trước thì code sẽ như sau:

$factory->define(App\Model\User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'contact_number' => $faker->phoneNumber,
    ];
});

Trong file UsersTableSeeder.php code sẽ thay đổi như sau:

public function run()
{
	factory(App\Models\Users::class)->create();
}

Sau khi chạy lện seeder trên Terminal thì chúng ta cũng sẽ thu được một bộ dữ liệu của người dùng đảm bảo đầy đủ 3 trường dữ liệu là tên, email và số điện thoại.

Trong một số trường hợp, chúng ta không cần thiết phải tạo ra qua nhiều bản ghi mà chỉ cần tạo ra một số bản ghi. Để tùy chỉnh số lượng bản ghi factory sinh ra, chúng ta thao tác như sau:

public function run()
{
	factory(App\Models\Users::class, 'number_of_rows')->create();
}

Ví dụ, chúng ta muốn tạo ra 3 dữ liệu của 3 người khác nhau. Chúng ta chạy lệnh:

public function run()
{
	factory(App\Models\Users::class, 3)->create();
}

Một vấn đề mới được đặt ra là. Việc gọi $fake->name hay $faker->email sẽ sinh ra dữ liệu khá dài dòng, đôi khi khó đọc khó nhớ. Vậy trong trường hợp chúng ta muốn custom tên người hay địa chỉ email thì phải làm thế nào? Factory cũng rất linh hoạt cho phép chúng ta thao tác những điều này một cách dễ dàng.

public function run()
{
	factory(App\Models\Users::class, 3)->create([
    	'name' => 'CanhNV',
        'email' => '[email protected]'
    ]);
}

Khi chúng ta truyền tham số vào hàm create() như trên thì factory sẽ tự động lấy thông tin chúng ta truyền vào làm dữ liệu chứ không gọi hàm sinh random giá trị như trước nữa.

Vậy là chúng ta đã có được một bộ dữ liệu như y muốn.

Trong nhiều trường hợp, chúng ta định nghĩa một Model Factories nhưng Factory này chỉ đúng trong một số trường hợp nhất định, còn một số trường hợp khác thì Factory này không đáp ứng được điều kiện dữ liệu. Để khắc phục tình trạng này chúng ta có định nghĩa Multiple Factory Types.

$factory->defineAs(App\Model\Users::class, 'withNoId', function ($faker) use ($factory) {
    'name' => $faker->name,
    'email' => $faker->email,
});

Chúng ta truyền vào một tham số mới để phân biệt với Factory đã định nghĩa từ trước.

Khi tiến hành gọi đến Factory này thì gọi như sau:

factory(App\Model\Users::class, 'withNoId')->make();

Factory make vs create methods

Trong ví dụ cuối cùng, các bạn có thể thấy thay vì gọi đến method create() như trước đây thì tôi lại gọi method make(). Đây là hai method thực hiện hai chức năng hoàn toàn khác nhau. Create thì lưu trữ dữ liệu vào trong database nó giống như lưu trữ với Eloquent. Make thì hoàn toàn khác. Nó tạo ra dữ liệu nhưng không insert dữ liệu vào trong database.

Trên đây là một vài đặc điểm của Faker và cách sử dụng nó với Model Factories. Chúc các bạn nghiên cứu và sử dụng thư viện này thành công trong công việc. ^^