2009-07-16 29 views
12

Tôi có một ứng dụng web PHP được xây dựng với khuôn khổ CodeIgniter MVC. Tôi muốn kiểm tra các lớp điều khiển khác nhau. Tôi đang sử dụng Toast để kiểm tra đơn vị. Bộ điều khiển của tôi không có trạng thái, mọi thứ mà chúng xử lý đều được lưu vào phiên hoặc được chuyển tới để hiển thị. Tạo một đối tượng phiên giả lập và kiểm tra xem nó có hoạt động đúng hay không đơn giản (chỉ cần tạo một đối tượng giả và tiêm nó với $ controller-> session = $ mock).Làm cách nào để kiểm tra bộ điều khiển bằng CodeIgniter?

Điều tôi không biết, là cách làm việc với chế độ xem. Trong CodeIgniter, lượt xem được tải dưới dạng:

$this->load->view($view_name, $vars, $return); 

Vì tôi không muốn thay đổi mã CI, mặc dù tôi có thể tạo bộ nạp giả và thay thế bản gốc. Và đây là vấn đề, tôi không thể tìm ra cách để lấy được một lớp mới từ CI_Loader.

Nếu tôi không bao gồm các hệ thống/thư viện/Loader.php tập tin, các CI_Loader lớp là undefined và tôi không thể kế thừa từ nó:

class Loader_mock extends CI_Loader 

Nếu tôi làm bao gồm các tập tin (sử dụng require_once), tôi nhận được lỗi:

Cannot redeclare class CI_Loader 

Trông như mã CI tự nó không sử dụng require_once từ bất cứ lý do gì.

Có ai ở đây có kinh nghiệm với đơn vị kiểm tra các ứng dụng được hỗ trợ CodeIgniter không?

Edit: Tôi cố gắng để tiêm một đối tượng loader thực tại thời gian chạy vào một lớp học giả, và chuyển hướng tất cả các cuộc gọi và các biến với __call, __set, __get, __isset và __unset. Nhưng, nó dường như không hoạt động (tôi không nhận được bất kỳ lỗi mặc dù, chỉ cần không có đầu ra, tức là trang trống từ bánh mì nướng). Đây là mã:

class Loader_mock 
{ 
    public $real_loader; 
    public $varijable = array(); 

    public function Loader_mock($real) 
    { 
     $this->real_loader = $real; 
    } 

    public function __call($name, $arguments) 
    { 
     return $this->real_loader->$name($arguments); 
    } 

    public function __set($name, $value) 
    { 
     return $this->real_loader->$name = $value; 
    } 

    public function __isset($name) 
    { 
     return isset($this->real_loader->$name); 
    } 

    public function __unset($name) 
    { 
     unset($this->loader->$name); 
    } 

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

    public function view($view, $vars = array(), $return = FALSE) 
    { 
     $varijable = $vars; 
    } 
} 

Trả lời

4

Ngoài ra, bạn có thể làm điều này:

$CI =& get_instance(); 
$CI = load_class('Loader'); 

class MockLoader extends CI_Loader 
{ 
    function __construct() 
    { 
     parent::__construct(); 
    } 
} 

Sau đó, trong điều khiển của bạn làm $ this-> load = MockLoader mới().

+0

Ý tưởng hay, cảm ơn. –

2

Giải pháp hiện tại của tôi là thay đổi mã CodeIgniter để sử dụng require_once thay vì yêu cầu. Đây là bản vá tôi sẽ gửi cho các nhà phát triển CI trong trường hợp ai đó cần phải làm như vậy cho đến khi họ chấp nhận nó:

diff --git a/system/codeigniter/Common.php b/system/codeigniter/Common.php 
--- a/system/codeigniter/Common.php 
+++ b/system/codeigniter/Common.php 
@@ -100,20 +100,20 @@ function &load_class($class, $instantiate = TRUE) 
     // folder we'll load the native class from the system/libraries folder. 
     if (file_exists(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT)) 
     { 
-    require(BASEPATH.'libraries/'.$class.EXT); 
-    require(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT); 
+    require_once(BASEPATH.'libraries/'.$class.EXT); 
+    require_once(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT); 
       $is_subclass = TRUE; 
     } 
     else 
     { 
       if (file_exists(APPPATH.'libraries/'.$class.EXT)) 
       { 
-      require(APPPATH.'libraries/'.$class.EXT); 
+      require_once(APPPATH.'libraries/'.$class.EXT); 
         $is_subclass = FALSE; 
       } 
       else 
       { 
-      require(BASEPATH.'libraries/'.$class.EXT); 
+      require_once(BASEPATH.'libraries/'.$class.EXT); 
         $is_subclass = FALSE; 
       } 
     } 
1

Tôi không thể giúp bạn nhiều với thử nghiệm, nhưng tôi có thể giúp bạn mở rộng Thư viện CI.

Bạn có thể tạo lớp học MY_Loader của riêng bạn bên trong /application/libraries/MY_Loader.php.

<?php 
    class MY_Loader extends CI_Loader { 

    function view($view, $vars = array(), $return = FALSE) { 
     echo 'My custom code goes here'; 
    } 

    } 

CodeIgniter sẽ tự động thấy điều này. Chỉ cần đặt vào các hàm bạn muốn thay thế trong thư viện gốc. Mọi thứ khác sẽ sử dụng bản gốc.

Để biết thêm thông tin, hãy xem CI manual page for creating core system classes.

+3

+1 cho ý tưởng. Tuy nhiên, một quy tắc vàng của thử nghiệm đơn vị là bạn không cần phải sửa đổi hệ thống chỉ để kích hoạt móc cho các bài kiểm tra đơn vị. Lý tưởng nhất, các lớp không thuộc bộ kiểm thử đơn vị không được có bất kỳ hành lý kiểm tra đơn vị nào với chúng. Ngoài ra, việc giữ tất cả mã kiểm tra đơn vị cho một lớp kiểm tra trong cùng một tệp giúp việc quản lý dễ dàng hơn nhiều (và cũng loại bỏ mã thử nghiệm đơn vị khi triển khai vào sản xuất). –

1

Tôi bị ấn tượng bởi mã bạn đang cố gắng sử dụng.

Vì vậy, bây giờ tôi tự hỏi làm thế nào lớp 'Hooks' của CodeIgniter có thể giúp ích gì cho vấn đề của bạn?

http://codeigniter.com/user_guide/general/hooks.html

Trân trọng! Rein Groot

+0

+1 cho mẹo. Có vẻ như nó có thể làm được, nhưng theo cách hơi khó xử. Thay vào đó, tôi quyết định vá CodeIgniter - đó là một thay đổi đơn giản và tôi hy vọng nó sẽ được chuyển thành mã CI chính thống một ngày (vì tôi không thấy bất kỳ lý do nào tại sao nó không nên), vì vậy tôi sẽ không phải vá nó khi các phiên bản mới được phát hành. –

0

Bộ điều khiển không được chứa logic miền, vì vậy các kiểm tra đơn vị không có ý nghĩa ở đây.

Thay vào đó, tôi sẽ kiểm tra bộ điều khiển và chế độ xem với các kiểm tra chấp nhận.

+0

Vâng ... trong khi không có logic miền trong bộ điều khiển, chúng * chịu trách nhiệm quản lý đầu vào của người dùng. Và thay đổi trạng thái của lớp mô hình dựa trên đầu vào đó. Đó là nơi mọi người sẽ tập trung vào các bài kiểm tra đơn vị cho các bộ điều khiển. –

+0

Tôi không nghĩ rằng bộ điều khiển nên thay đổi trạng thái của bất cứ điều gì trong lớp mô hình. Nó sẽ chỉ nhận được yêu cầu và sau đó chuyển nó đến lớp mô hình (sau khi xử lý bảo mật web, v.v.). Nếu bạn đang thay đổi các thực thể hoặc dữ liệu thì tôi đoán bạn sẽ cần kiểm tra. Nhưng bạn không nên làm điều đó ngay từ đầu. – Patrick

+1

Nếu bạn vượt qua tên người dùng và mật khẩu để mô hình lớp, bạn đang thay đổi trạng thái của nó. Hoặc nếu bạn gửi một tiêu đề của bài viết được lưu, bạn cũng đang thay đổi trạng thái của lớp mô hình. Và cái mà bạn gọi là "bảo mật web" là cái gì đó nên được thực hiện trong lớp mô hình (có thể ngoại trừ việc ngăn chặn CSRF ... có thể được thực hiện tốt hơn khi khởi tạo thể hiện 'Request'). Mặc dù, có thể là chúng tôi đang sử dụng cùng một thuật ngữ cho [khái niệm] hoàn toàn khác nhau (http://stackoverflow.com/a/5864000/727208). –

Các vấn đề liên quan