Khẳng định trong php

Để hiểu rõ hơn về TDD và sử dụng nó trong thực tế, chúng ta tiếp tục tìm hiểu TDD thông qua phần 2. Sử dụng TDD với framework Laravel nhé

Các bạn cũng có thể xem lại phần 1 để hiểu rõ hơn về mô hình TDD. Phần 1. Giới thiệu về TDD, cách hoạt động, nhưng lợi ích và vấn đề gặp phải khi sử dụng TDD

I. Chu trình của TDD

Như phần 1 đã có chủ đề cập nhật, Test-Driven Development (TDD) là một cách phát triển phần mềm nhấn mạnh vào việc viết các Test-case trước để chỉ định những logic mà mã nguồn sẽ thực hiện

Một chu trình của TDD sẽ bao gồm

  1. viết test-case
  2. Chạy trường hợp thử nghiệm đã viết và sẽ nhận được kết quả không thành công do không có mã nguồn được viết
  3. Viết mã nguồn (code) để trả lời test-case
  4. Chạy lại trường hợp kiểm tra để kiểm tra mã nguồn đã được viết và trả lời chưa
  5. Correction code source to pass test-case (refactor)
  6. lặp lại bước re-run (4) và refactor (5) cho đến khi test-case được pass

Khẳng định trong php

II. Áp dụng TDD trong Laravel 7

Để hiểu rõ hơn về việc áp dụng TDD trong Laravel như thế nào, chúng ta sẽ bắt đầu từng bước với chức năng bổ sung thêm 1 người dùng mới nhé.

1. Standard is the field

Trước khi bắt đầu viết mã, các bạn cần có một môi trường để có thể chạy ứng dụng web php

  • Phiên bản PHP 7. 0 trở lên với Xdebug 3
  • nhà soạn nhạc. https. //getcomposer. tổ chức/tải xuống
  • Git. https. //github. com/git-guides/install-git

Trong bài viết này, mình sử dụng Cloud9 trên AWS để tạo IDE có thể code được luôn, các bạn có thể xem thêm tại Tạo môi trường trên AWS Cloud9. Chi tiết môi trường sử dụng

ec2-user:~/environment $ git --version
git version 2.32.0
ec2-user:~/environment $ php composer.phar -V
Composer version 2.3.7 2022-06-06 16:43:28
ec2-user:~/environment $ php -v
PHP 7.2.24 (cli) (built: Oct 31 2019 18:27:08) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v3.1.5, Copyright (c) 2002-2022, by Derick Rethans

2. Khởi tạo dự án laravel

Sử dụng composer để tạo project laravel
php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 

đầu ra

ec2-user:~/environment $ php composer.phar create-project laravel/laravel example_tdd
Creating a "laravel/laravel" project at "./example_tdd"
Info from https://repo.packagist.org: #StandWithUkraine
Installing laravel/laravel (v7.30.1)
........
Package manifest generated successfully.
69 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan key:generate --ansi
Application key set successfully.
Chỉnh sửa file config

Các test-case sử dụng các giá trị trong tệp phpunit. xml doing config when running. Mỗi lần thực thi thì nên làm mới cơ sở dữ liệu, nghĩa là nó sẽ xóa sạch cơ sở dữ liệu và chạy lại di chuyển mỗi lần thực thi. Vì vậy, chúng ta không nên sử dụng cơ sở dữ liệu chung của mã môi trường (local, dev) và cơ sở dữ liệu của bài kiểm tra.
Ở bước này, chúng ta sẽ cài đặt cơ sở dữ liệu riêng để sử dụng cho công việc kiểm tra. Open file phpunit. xml và bỏ comment 2 dòng sau.

  
  

Với cấu hình này, thì khi chạy thử nghiệm, hệ thống sẽ sử dụng DB kiểu sqlite và DB này sẽ được lưu vào RAM, vì vậy, chúng ta không cần thiết phải cài đặt hay tạo cơ sở dữ liệu riêng. And the clock,việc lưu vào RAM sẽ giúp test-case chạy nhanh hơn

Lưu ý. Trong dự án thực tế, thường sẽ sử dụng biến môi trường. env chứa các giá trị của môi trường mà bạn đang code, ví dụ local, dev, production. Thì với trường hợp test, chúng ta sẽ tạo 1 file. env. thử nghiệm, khi chạy thử nghiệm, hệ thống sẽ sử dụng các giá trị trong tệp. env. thử nghiệm thay cho. env

Cố gắng chạy thử nghiệm với các trường hợp demo có sẵn với cú pháp của phpunit

./vendor/bin/phpunit

Hoặc sử dụng câu lệnh của Laravel Artisan để dễ phát triển và gỡ lỗi hơn với đầu ra được hiển thị dễ nhìn hơn

php artisan test

đầu ra

ec2-user:~/environment/example_tdd $ php artisan test

PASS  Tests\Unit\ExampleTest
✓ basic test

PASS  Tests\Feature\ExampleTest
✓ basic test

Tests:  2 passed
Time:   0.15s

Như vậy là chúng ta đã hoàn thành chuẩn bị để viết test-case. Bây giờ bắt tay vào viết Unit-Test cho màn hình quản lý người dùng nhé

3. Viết UnitTest theo mô hình TDD

Để có thể viết được test-case, chúng ta cần hiểu chức năng này hoạt động như thế nào (phân tích bài toán), sau đó sẽ nghĩ đến giải pháp thực thi chức năng (thiết kế mã luồng). Ví dụ trong API thêm người dùng mới, chúng ta sẽ thiết kế các bước như sau

  • beforeAddUser. Thực hiện xác thực, chuẩn hóa dữ liệu nhận được trước khi chèn vào cơ sở dữ liệu
  • doAddUser. Thực hiện việc chèn dữ liệu người dùng đã được chuẩn hóa vào cơ sở dữ liệu
  • afterAddUser. Xử lý chèn kết quả, chuẩn hóa để định dạng đúng trả về cho khách hàng

UnitTest thường được sử dụng để kiểm tra các chức năng nhỏ phục vụ công việc tính toán hoặc chuyển đổi dữ liệu. FeatureTest thường được sử dụng để kiểm tra chức năng hoàn chỉnh như chức năng bổ sung, chỉnh sửa, xóa. Vì vậy, chúng ta sẽ thiết kế test-case như sau

  • test_before_add_user. UnitTest cho method beforeAddUser
  • test_after_add_user. UnitTest cho phương thức afterAddUser
  • quản trị viên_can_add_user. FeatureTest cho cả chức năng addUser

Trong bài viết này, mình sẽ hướng dẫn viết test_before_add_user theo TDD, 2 case test còn lại thì cũng sẽ làm tương tự nhé

TestCase cơ sở mã. php

Khi cần gọi đến các phương thức bảo vệ/riêng tư hoặc thay đổi thuộc tính trong lớp, ta sẽ sử dụng \ReflectionClass để thực hiện được. Để tránh phải viết lại mã xử lý logic này, chúng ta thêm đoạn mã sau vào các bài kiểm tra/TestCase. php

 /**
 * Get private/protected property value
 */
public function getObjectProperty($object, $propertyName) {
    $reflector = new \ReflectionClass(get_class($object));
    $property = $reflector->getProperty($propertyName);
    $property->setAccessible(true);

    return $property->getValue($object);
}

/**
 * Call protected/private method of a class.
 */
public function invokeObjectMethod($object, $methodName, $parameters = [])
{
    $reflection = new \ReflectionClass(get_class($object));
    $method = $reflection->getMethod($methodName);
    $method->setAccessible(true);

    return $method->invokeArgs($object, $parameters);
}
UnitTest beforeAddUser

Bước 1. Viết TestCase mới
Sử dụng Laravel Artisan để tạo Test.

________số 8

Sau khi chạy lệnh, tệp UserUnitTest. php sẽ được tạo trong đường dẫn tests/Unit

Chú thích

  • Tên của lớp kiểm tra phải được đặt theo quy tắc *Test, nếu muốn thay đổi, bạn có thể sửa trong tệp phpunit. xml
  • Để PHPUnit biết phương thức nào trong lớp cần chạy thử nghiệm, thì tên của phương thức đó cần phải có tiếp tục ngôn ngữ kiểm tra, ví dụ test_user_show hoặc sử dụng chú thích /** @test */
    UnitTest cho beforeAddUser:
/**
 * Test beforeAddUser 
 *
 * @test
 */
public function test_before_add_user()
{
    // input data 
    $dataInput = [
        'first_name' => $this->faker->firstName(),
        'last_name' => $this->faker->lastName(),
        'email' => $this->faker->email,
        'password' => $this->faker->password,
    ];

    // execute
    $output = $this->invokeObjectMethod(new \App\Http\Controllers\UserController(), 'beforeAddUser', [$dataInput]);

    // expect data
    $dataExpect = [
        'name' => $dataInput['first_name'] . ' ' . $dataInput['last_name'],
        'email' => $dataInput['email'],
        'password' => $dataInput['password'], 
    ];

    // assert
    $this->assertEquals($output, $dataExpect);
}

Bước 2. Chạy TestCase
Chạy thử, chúng ta sẽ thấy có lỗi xảy ra do chưa có code.

php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
0

Bước 3. Viết mã để trả lời ứng dụng được TestCase vừa tạo
Tạo UserController.

php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
1
php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
2

Bước 4. Chạy lại UnitTest

php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
3

-> Lỗi do mã logic trả về dữ liệu không chính xác

Bước 5. Edit code to pass UnitTest

php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
4

lặp lại bước 4 và bước 5 cho đến khi vượt qua UnitTest

php composer.phar create-project laravel/laravel example_tdd
cd example_tdd 
5

-> Đã vượt qua Bài kiểm tra Đơn vị và phương thức trước khi Thêm người dùng đã hoạt động theo đúng logic mà chúng tôi đã phân tích và thiết kế ban đầu

Như vậy chúng ta đã hoàn thành xử lý logic cho beforeAddUser, các phần khác trong thiết kế chúng ta sẽ thực hiện các bước tương tự