Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
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.
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ẽ nhận được các thông báo dạng như sau:
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:
Bạn cần cài đủ những plug-in sau:
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
Mở tiếp sang tab Unit Testing:
Bấm nút Search trong phần PHPUnit Script để Netbeans tự động xác định PHPUnit.
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.
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:
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 Java\C++\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:
Giờ ta cần xây dựng một lớp (class) như sau cho project của mình:
Cụ thể trên Netbeans như sau:
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:
Đây là code tôi viết cho class này (thực tế phần lớn là do Netbeasn tự sinh ra :P )
<?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):
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:
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:
Để đỡ 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:
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:
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!