2009-07-16 10 views
12

Tengo una aplicación web PHP construida con framework CodeIgniter MVC. Deseo probar varias clases de controlador. Estoy usando Toast para pruebas unitarias. Mis controladores no tienen estado, todo lo que procesan se guarda en la sesión o se pasa a la vista para mostrar. Crear un objeto de sesión simulado y probar si funciona correctamente es sencillo (solo crea un objeto falso e inyéctalo con $ controller-> session = $ mock).¿Cómo probar los controladores con CodeIgniter?

Lo que no sé, es cómo trabajar con vistas. En CodeIgniter, las vistas se cargan como:

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

Ya que no quiero alterar el código IC, aunque yo podría crear una maqueta del cargador y reemplazar el original. Y aquí radica el problema, no puedo encontrar una manera de derivar una nueva clase de CI_Loader.

Si no incluyo el sistema de bibliotecas de archivos// Loader.php, la CI_Loader clase no está definido y no puede heredar de ella:

class Loader_mock extends CI_Loader 

Si hago incluir el archivo (utilizando require_once), Obtengo el error:

Cannot redeclare class CI_Loader 

Parece que el código CI en sí mismo no utiliza require_once por ningún motivo.

¿Alguien aquí tiene experiencia con pruebas unitarias de aplicaciones con motor CodeIgniter?

Editar: Me trataron de inyectar un objeto cargador real en tiempo de ejecución en un simulacro de clase, y redirigir todas las llamadas y las variables con __call, __set, __get, __isset y __unset. Pero, parece que no funciona (no obtengo ningún error, simplemente no hay salida, es decir, una página en blanco de Toast). Aquí está el código:

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; 
    } 
} 

Respuesta

4

Alternativamente, usted puede hacer esto:

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

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

Luego, en el controlador de hacer $ this-> carga = new MockLoader().

+0

Buena idea, gracias. –

2

Mi solución actual es el de alterar el código CodeIgniter usar require_once en lugar de requerir. Aquí está el parche que voy a enviar a los desarrolladores de CI en caso de que alguien tiene que hacer lo mismo hasta que acepten que:

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

no puedo ayudar mucho con la prueba, pero puedo ayudarle a ampliar el Biblioteca CI

Puede crear su propia clase MY_Loader dentro de /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 verá esto automáticamente. Simplemente coloque las funciones que desea reemplazar en la biblioteca original. Todo lo demás usará el original.

Para obtener más información, consulte CI manual page for creating core system classes.

+3

+1 para la idea. Sin embargo, una regla de oro de las pruebas unitarias es que no debería necesitar modificar el sistema solo para habilitar los ganchos para las pruebas unitarias. Idealmente, las clases que no forman parte del conjunto de pruebas de unidad no deberían tener ninguna unidad de equipaje de prueba con ellos. Además, mantener todos los códigos de prueba de la unidad para una sola clase de pruebas en el mismo archivo hace que sea mucho más fácil de administrar (y también elimina el código de prueba de la unidad cuando se implementa en producción). –

1

Estoy impresionado por el código que está tratando de usar.

Así que ahora me pregunto cómo la clase 'Hooks' de CodeIgniter podría ser de alguna ayuda para su problema?

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

Saludos cordiales, rienda Groot

+0

+1 para la propina. Parece que podría ser factible, pero de una manera un tanto incómoda. Decidí parchar CodeIgniter en su lugar, es un cambio simple, y espero que algún día llegue al código principal de CI (ya que no veo ninguna razón por la que no debería), así que no tendré que parcharlo cuando nuevas versiones son lanzadas. –

0

El controlador no debe contener lógica de dominio, por lo que las pruebas unitarias no tienen sentido aquí.

En cambio, probaría los controladores y las vistas con pruebas de aceptación.

+0

Bueno ... si bien no hay lógica de dominio en los controladores, * son * responsables de administrar la entrada del usuario. Y alterando el estado de la capa del modelo en función de esa entrada. Ahí es donde uno se enfocaría en las pruebas unitarias para los controladores. –

+0

No creo que el controlador deba alterar el estado de nada en la capa del modelo. Simplemente debería recibir la solicitud y luego pasarla a la capa del modelo (después de manejar la seguridad web, etc.). Si está alterando entidades o datos, entonces supongo que debería probar. Pero no deberías estar haciendo eso en primer lugar. – Patrick

+1

Si transfiere el nombre de usuario y la contraseña a la capa del modelo, está alterando el estado del mismo. O si envía un título del artículo para guardar, también está alterando el estado de la capa del modelo. Y lo que usted llamó "seguridad web" es algo que debería realizarse en la capa de modelo (tal vez excepto la prevención de CSRF ... que podría realizarse mejor al inicializar la instancia de 'Solicitud '). Sin embargo, es posible que usemos el mismo término para [conceptos] completamente diferentes (http://stackoverflow.com/a/5864000/727208). –

Cuestiones relacionadas