Tag Archives: PHP

PHPUnit

Kiểm thử đơn vị với PHPUnit trên Netbeans

Nguyễn Việt Khoa

Khái niệm Kiểm thử đơn vị (Unit Testing) không còn xa lạ với những lập trình viên luôn hướng tới chất lượng của từng dòng code. Với bài viết này tôi mong muốn sẽ giúp các lập trình viên PHP biết cách triển khai Unit Testing với framework PHPUnit. Đây là một Framework nổi tiếng thế giới, nó cho phép bạn triển khai Unit Testing với nhiều IDE khác nhau, ở bài viết này tôi sẽ hướng dẫn bạn triển khai với Netbeans 7.2.

Netbeans là IDE được nhiều lập trình viên Java sử dụng, tuy vậy đây cũng là một trong những IDE hỗ trợ lập trình PHP và đặc biệt là hỗ trợ đắc lực cho việc triển khai kiểm thử tự động với PHPUnit.

Trước hết để có thể triển khai ứng dụng với PHP bạn cần có môi trường cho ngôn ngữ này đã. Bạn dễ dàng làm quen với PHP và chuẩn bị môi trường để phát triển ứng dụng (web) với ngôn ngữ này. Về mặt căn bản bạn chỉ cần cài XAMPP là đủ để phát triển ứng dụng web với PHP, nếu không cần đi quá sâu về môi trường phát triển PHP.

Có thể bạn đã có XAMPP, tuy nhiên PHPUnit cần phải có thêm sự hỗ trợ của PEAR. Hướng dẫn cài PEAR có khá nhiều trên Internet, ví dụ như trang web http://www.phpunit.de.  Hoặc bạn có thể thực hiện các lệnh như tôi đã làm trên màn hình lệnh của Windows (cũng có thể bạn có cách khác đơn giản hơn? cho chúng tôi cùng biết với nhé). Lưu ý, nếu bạn dùng Windows với tài khoản thường thì cần phải chạy CMD (chương trình để chạy các lệnh) với quyền của Administrator (Run as Administrator), đặc biệt là trên Windows 8.

setup1

Lưu ý lệnh cài đặt PHPUnit với PEAR (dòng lệnh thứ 2) chỉ thực hiện được thành công với những điều kiện sau:

  • Bạn đã sẵn có XAMPP và đang vào đúng thư mục php nằm trong thư mục cài đặt của nó (tôi đang có XAMPP ở tại C:xampp).
  • Máy tính của bạn phải được kết nối Internet vì lệnh cài đặt trên sẽ tải bộ cài từ repo trên mạng về trước khi cài vào máy tính của bạn.

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

setup2

Nếu toàn thấy “OK” như trên thì chắc bạn đã thành công và PHPUnit đã sẵn sàng để bạn xài nó. Nếu báo lỗi bạn cần chạy lệnh sau:

pear config-set auto_discover 1

Sau đó chạy lại lệnh:

pear install pear.phpunit.de/PHPUnit

Nếu vẫn có lỗi thì hiện tại tôi chưa đoán biết được bạn đang gặp vấn đề gì cả :o)

Bây giờ là lúc bạn cần kiểm tra xem Netbeans bạn đang dùng đã hỗ trợ PHP chưa? Nếu chưa bạn có hai lựa chọn sau:

  1. Tải bản Netbeans hỗ trợ PHP và cài đặt nó: http://netbeans.org/downloads/index.html
  2. Sử dụng công cụ cài đặt plug-in của Netbeans để tìm các plug-in về PHP:

PHP-plug-in

Bạn cần cài đủ những plug-in sau:

  1. PHP
  2. Selenium Module for PHP
  3. PHP Documentor Tag Help
  4. PHP Documentor

Những plug-in trên ngoài việc hỗ trợ viết PHP nó còn giúp bạn triển khai Unit Testing ngay trên Netbeans với PHPUnit.

Việc tiếp theo là kiểm tra xem Netbeans đã nhận PHPUnit chưa theo các bước sau: Từ thanh trình đơn của Netbeans > Tools > Options > chọn tab PHP

php-options

Mở tiếp sang tab Unit Testing:

php-options2

Bấm nút Search trong phần PHPUnit Script để Netbeans tự động xác định PHPUnit.

php-options3

Bấm nút Search trong phần Skeleton Generator Script để Netbeans tự động xác định công cụ sinh ra các mã dành cho Unit Testing.

php-options4

Sau khi 2 script này được xác định bạn đã sẵn sàng cho những Kiểm thử đơn vị đầu tiên rồi.

Vấn đề lúc này là: bạn đã biết căn bản về PHP chưa? Nếu câu trả lời là chưa! Xin mời bạn tìm hiểu trước về PHP ở loạt bài sau:

  1. Bắt đầu với PHP và CMS
  2. [PHP] Những dòng code đầu tiên
  3. [PHP] Các cấu trúc điều kiện
  4. [PHP]Các cấu trúc lặp
  5. [PHP]Quy ước đặt tên

Hoặc tự tìm hiểu ở những nguồn phong phú hơn như www.php.net hay w3schools.com. Tuy nhiên với những dòng code mà tôi sử dụng dưới đây, bạn không nên lo lắng về trình PHP của mình (chỉ cần bạn đã biết về OOP với JavaC++C#v.v..)

Nếu câu trả lời là OK, chúng ta cùng nhau đi tiếp từ đây.

Bước đầu tiên của công đoạn này, bạn cần tạo một project PHP trên Netbeans, VD project của tôi là DemoPHP:

php-prj

php-prj2

php-prj3

php-prj4

Giờ ta cần xây dựng một lớp (class) như sau cho project của mình:

Person-Class

Cụ thể trên Netbeans như sau:

php-class

Bạn nên đưa các class vào một thư mục để tiện quản lý, VD tôi đưa chúng vào thư mục classes:

php-class2

Đây là code tôi viết cho class này (thực tế phần lớn là do Netbeasn tự sinh ra 😛 )

<?php
/*
** Description of Person
** @author KhoaNV
*/
class Person {
	private $name;
	private $gender;
	private $age;

	function __construct($name, $gender, $age) {
		$this->name = $name;
		$this->gender = $gender;
		$this->age = $age;
	}

	public function getName() {
		return $this->name;
	}

	public function setName($name) {
		$this->name = $name;
	}

	public function getGender() {
		return $this->gender;
	}

	public function setGender($gender) {
		$this->gender = $gender;
	}

	public function getAge() {
		return $this->age;
	}

	public function setAge($age) {
		$this->age = $age;
	}

	public function sayHello($otherName){
		throw new Exception("Error!");
	}

	public function sayGoodbye($otherName){
		throw new Exception("Error!");
	}
}
?>

Bạn lưu ý là Netbeans hỗ trợ tự động sinh các code căn bản cho một class trong PHP (sử dụng tổ hợp phím Alt+Insert):

php-class3

Tôi chưa vội hoàn chỉnh hàm sayHello và sayGoodbye, vì cái chúng ta đang cần là Unit Testing với PHPUnit và tôi thì thích triển khai nó theo TDD. Do đó, tôi sẽ tạo một test (kiểm thử) cho lớp Person, cụ thể là cho phương thức sayHello. Netbeans với những plug-in mà bạn cài đặt ở trên sẽ dễ dàng giúp bạn tạo ra cái test này. Bạn nên tạo một thư mục để chứa các test, VD tôi đặt thư mục này là tests (cùng thư mục cha với thư mục classes). Mời bạn quan sát hình ảnh sau:

php-unittest

Nếu không gặp lỗi gì, bạn sẽ có một lớp mới dùng để test cho lớp Person vừa tạo ở trên:

php-unittest2

Để đỡ mất tập trung vào các hàm test khác (tự sinh ra bởi công cụ) bạn có thể xóa hết các hàm có trong lớp PersonTest này và chỉ để lại hàm test cho sayHello:

<?php
/**
 * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-03-23 at 15:45:45.
 */
require_once '../../classes/Person.php';

class PersonTest extends PHPUnit_Framework_TestCase {

    /**
     * @covers Person::sayHello
     * @todo   Implement testSayHello().
     */
    public function testSayHello() {
         $this->markTestIncomplete(
                'This test has not been implemented yet.'
        );
    }

}

Giờ ta cần hoàn chỉnh một test-case để kiểm tra tính đúng đắn của sayHello. Mời bạn xem đoạn code sau:

<?php
/**
 * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-03-23 at 15:45:45.
 */
require_once '../../classes/Person.php';

class PersonTest extends PHPUnit_Framework_TestCase {

    /**
     * @covers Person::sayHello
     * @todo   Implement testSayHello().
     */
    public function testSayHello() {
        $expected = "Hello TapChiLapTrinh. I'm Khoa";
        $person = new Person("Khoa", true, 18);

        $this->assertEquals($expected, $person->sayHello('TapChiLapTrinh'));
    }

}

Lưu ý dòng code “require_once ‘../../classes/Person.php’;” dùng để xác định nơi chứa code của lớp mà bạn muốn test. Tôi không hiểu sao nó không được tự động chèn vào? Hiện tôi tự code dòng đó, nếu bạn biết cách nào đó mà không phải làm vậy, xin hãy khai sáng cho tôi.

Bạn hãy chạy thử test-case này để kiểm tra kết quả (nhấp chuột phải vào và chọn Run File hoặc nhấp chuột phải vào lớp Person và chọn Test). Chắc chắn nếu bạn chưa hoàn chỉnh code của hàm sayHello thì bạn sẽ nhận được thông báo như sau:

run-test

Nếu bạn nhận được thông báo như trên thì bạn đã có tín hiệu vui mừng đầu tiên trong TDD,  “Red: Create a test and make it fail”.

Nào, bây giờ thì chúng ta quay lại để hoàn tất code của hàm sayHello.

public function sayHello($otherName){
    $strTemp = trim($otherName);
    if($strTemp!=''){
        return "Hello " . $otherName . ". I'm " . $this->name;
    }
    throw new Exception("Error!");
}

Vòng lại bước chạy test-case xem sao nào? Nếu bạn vẫn nhận được Red, chắc là bạn cần xem lại code của hàm sayHello. Còn với tôi kết quả là như sau:

run-test2

Tôi có thể vui được rồi, vì mình đã hoàn tất khâu tiếp theo trong TDD đó là “Green: Make the test pass by any means necessary”.

Đến đây tôi xin tạm dừng bài viết của mình, tôi nghĩ rằng lúc này bạn đã có thể tự mình triển khai Unit Testing với PHPUnit được rồi :o)

Bạn có thể tham khảo thêm ở đây.

Chúc bạn thành công!

Nguyễn Việt Khoa