Как при тестировании с PHPUnit создать несуществующий класс, не объект!

seine

Новичок
Как при тестировании с PHPUnit создать несуществующий класс, не объект!

Привет всем
Есть класс Page, а в конструкторе есть такая строчка:

PHP:
$this->validator = new Validator();
Т.е. создаю делегата (кажется это так называется) validator, потом в других методах я его использую так:

PHP:
$this->validator->valideCaption($caption);
Класса Validator еще нет, хотя тут даже суть не в том есть он или нет. Он используется для проверки допустимости заголовка страницы.
Есть класс, который тестирует Page, вот он:

PHP:
class PageTest extends PHPUnit_Framework_TestCase
{
    public function testAddPage() {
        $page = new Page();
    }
}
Когда его запускаю, то PHPUnit ругается, что не найден класс Validator. Вот тут все и начианется, я добавил одну строчку и в итоге метод testAddPage() стал таким:

PHP:
    public function testAddPage() {
        $this->getMock('Validator', array('valideCaption'));
        $page = new Page();
    }

После этого ругань на отсутсвие класса прошла, но теперь PHPUnit ругается, что нет метода valideCaption, хотя я его тоже передаю (см. выше).
Вот собственно и вопрос, как сделать, чтобы Page мог вызывать несуществующие классы и определять методы для этих классов.
Мне кажется, что нужно использовать что-то другое вместо $this->getMock, но в документации ничего не нашел :-(
В примерах для SimpleTest есть такая фишка, по идее должна быть такая же и у PHPUnit... очень на это надеюсь.
 

HraKK

Мудак
Команда форума
У тебя нарушение архитектуры, а именно зависимости. Почитай на Агиле про управление зависимостями.
за место
PHP:
$this->validator->valideCaption($caption);
у тебя должно быть
PHP:
$this->getValidator()->valideCaption($caption);
а
PHP:
getValidator()
должен возвращать мок.

Чаще всего если ты видешь что тесты становятся толстыми или сложными это ты либо не правильно тестируешь, либо у тебя проблемы с архитектурой и пора задуматься о рефакторинге(почитай Фаулера "Рефакторинг").
 

whirlwind

TDD infected, paranoid
Ну а как ты хотел? Ты же инстанцируешь объект этого класса в тестируемом классе. На момент выполнения программы все классы должны быть известны - как чертежи. В твоем случае нужно использовать внутри класса то, что не требует инстанцирования - интерфейс. А для тестирования поведения конструктора (или где там у тебя вызывается $this->validator->valideCaption($caption)) следует использовать мок. Его можно впрыснуть в конструктор или через сеттер.
PHP:
public function testAddPage() { 
        // если Validator интерфейс, То
        $v = $this->getMock('Validator'); 
        $v->expect($this->once())
                ->method('validateCaption')
                ->with($this->equalTo('some value'))
                ->will($this->returnValue(true));
        $page = new Page($v);
        $page->сделатьЧтоНибуть():
    }
-~{}~ 27.06.10 15:53:

seine у тебя гдето непонимание в корне. Нельзя вызывать классы. Можно строить объекты по классам как по шаблонам или чертежам. И вызывать их методы. Методы принадлежат классам, но относятся к объектам.
 

seine

Новичок
Ага, понял, нельзя инстацировать объекты напрямую, а надо их передавать через конструктор или сеттер.

HraKK, можешь пояснить, как
PHP:
$this->getValidator()
может вернуть мок?

Правда теперь возник другой вопрос. На самом деле, я не спроста использовал
PHP:
$this->validator = new Validator();
Дело в том, что объект класса Page всегда использует один и тот же валидатор, и если передавать его каждый раз в конструкторе, то получится всегда делать ну как бы лишнюю работу что ли (и теоретически можно забыть передать его), а если Page кроме валидатора еще будет использовать пару других объектов, например драйвер БД и модель новостей, которые так же всегда постоянны для Page, это и их надо передавать в конструкторе?
Возможно, сейчас сильно торможу, но я не вижу альтернатив.
 

fixxxer

К.О.
Партнер клуба
Тут ты привязываешься к конкретной реализации по имени класса, что уже нехорошо. Лучше передавать реализацию в конструкторе или сеттером. Почитай таки http://wiki.agiledev.ru/doku.php?id=ooad:manage_dependencies_in_php_code

-~{}~ 27.06.10 18:01:

Если влом все переделывать можно просто заменить $this->validator на $this->getValidator() с lazy default-ом и добавиь setValidator(), как то так
PHP:
getValidator() {
   if (!isset($this->Validator)) {
      $this->Validator = $this->createDefaultValidator();
   }
   return $this->Validator;
}

setValidator(IValidator $Validator) {
    $this->Validator = $Validator;
}

createDefaultValidator() {
    return new Validator;
}
 

seine

Новичок
Спасибо всем, понял ошибку и теперь знаю как исправить.
Не ожидал, что такая активная помощь будет на форуме) т.е. вопрос довольно узкой направленности, думал, что ответов буду дольше ждать)
 

HraKK

Мудак
Команда форума
Наоборот, какой вопрос такой ответ. Хороший вопрос, хороший ответ.
 
Сверху