Как тестировать контроллеры с помощью CodeIgniter?
У меня есть веб-приложение PHP, созданное с помощью инфраструктуры CodeIgniter MVC. Я хочу протестировать различные классы контроллеров. Я использую Toast для модульного тестирования. У моих контроллеров нет состояния, все, что они обрабатывают, либо сохраняется в сеансе, либо передается на просмотр для отображения. Создание объекта mock session и проверка правильности его работы просто (просто создайте макет и добавьте его с помощью $controller- > session = $mock).
Я не знаю, как работать с представлениями. В CodeIgniter представления загружаются как:
$this->load->view($view_name, $vars, $return);
Так как я не хочу изменять код CI, я мог бы создать mock Loader и заменить оригинал. И здесь проблема, я не могу найти способ получить новый класс из CI_Loader.
Если я не включаю файл system/libraries/Loader.php, класс CI_Loader undefined, и я не могу наследовать его:
class Loader_mock extends CI_Loader
Если я действительно включаю файл (используя require_once), я получаю ошибку:
Cannot redeclare class CI_Loader
Похоже, что сам код CI не использует require_once по любой причине.
Есть ли у кого-нибудь опыт работы с модульными тестированиями приложений с поддержкой CodeIgniter?
Изменить: Я попытался внедрить реальный объект-загрузчик во время выполнения в класс-макет и перенаправить все вызовы и переменные с помощью __call, __set, __get, __isset и __unset. Но, похоже, это не работает (я не получаю никаких ошибок, но просто нет вывода, т.е. Пустой страницы из Toast). Здесь код:
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;
}
}
Ответы
Ответ 1
В качестве альтернативы вы можете сделать это:
$CI =& get_instance();
$CI = load_class('Loader');
class MockLoader extends CI_Loader
{
function __construct()
{
parent::__construct();
}
}
Затем в вашем контроллере выполните $this- > load = new MockLoader().
Ответ 2
Мое текущее решение - изменить код CodeIgniter, чтобы использовать require_once вместо require. Здесь патч, который я собираюсь отправить разработчикам CI, в случае, если кто-то должен сделать то же самое, пока не примет его:
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;
}
}
Ответ 3
Я не могу помочь вам в тестировании, но я могу помочь вам расширить библиотеку CI.
Вы можете создать свой собственный MY_Loader
класс внутри /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 увидит это автоматически. Просто вставьте функции, которые вы хотите заменить в исходной библиотеке. Все остальное будет использовать оригинал.
Для получения дополнительной информации ознакомьтесь с справочной страницей CI для создания основных системных классов.
Ответ 4
Меня впечатляет код, который вы пытаетесь использовать.
Итак, теперь мне интересно, как класс "Крюков" CodeIgniter может помочь вам в вашей проблеме?
http://codeigniter.com/user_guide/general/hooks.html
С уважением,
Рейн Грут
Ответ 5
Контроллер не должен содержать логику домена, поэтому модульные тесты здесь не имеют смысла.
Вместо этого я бы проверил контроллеры и представления с помощью приемочных тестов.