2TDD infected

HraKK

Мудак
Команда форума
Динамическая типизация зло и добро в одном лице, я думаю надо правильно и адекватно на это реагировать и следить за этим.
 

whirlwind

TDD infected, paranoid
Тут проблема даже не в самой типизации, а в том, что в сигнатурах нет возможности return type. Вот так навесишь мок на интерфейс, а потом соглашение о возвращаемом значении меняется. Мок не может определить когда этот момент наступает и класс-пользователь будет успешно работать по-старому, хотя по уму надо бы ему завалиться на тестах.
 

fixxxer

К.О.
Партнер клуба
Я кстати из за всей этой фигни часто делаю "недомоки" - просто подставляю свою реализацию, определенную в тесте, которая по сути выполняет функции мока.

Заодно помогает поддерживать низкую связанность - возможность заменить реализацию всегда приходится делать )

-~{}~ 01.02.10 12:17:

Но правда юнит тесты в чистом виде у меня редко получаются, все больше "2-3-юнита-тесты". :/ А все потому что лень...
 

HraKK

Мудак
Команда форума
просто подставляю свою реализацию, определенную в тесте, которая по сути выполняет функции мока.
чем это поможет при
Вот так навесишь мок на интерфейс, а потом соглашение о возвращаемом значении меняется.
?
 

korchasa

LIMB infected
whirlwind
Ну проверку можно и явно делать. Другое дело, что интерфейс используемых классов является частью инварианта того, кто их использует. Поэтому при обновлении, по идее, надо и название менять.
 

whirlwind

TDD infected, paranoid
korchasa ну да, это справедливо для определенного рода ситуаций. Мне чаще встречались прецеденты:

Интерфейс говорит что метод fetch должен возвращать IResultSet. Сначала это был ObjectResultSet implements IResultSet. Потом реализация поменялась и стал возвращаться TupleResultSet implements IResultSet (добавили Bulk Load). Интерфейс абсолютно неопорочен изменениями. Но вот беда, в тесте на метод fetch соответствующего датамаппера был навешан частичный мок, возвращающий мок, подтип, или любой другой дубль от ObjectResultSet. Тест, например контроллера зеленый, хотя должен валиться.

Эта ситуация, кстати, в вики agiledev упомянута в статье про моки, но примеров по этому поводу там нет. Тут никак не отследишь и не угадаешь. Выход я вижу только один - использовать моки как можно реже.

ЗЫ. точнее там сказано, что "мок возвращающий мок". Но по сути, это относится к любым дублям на любые методы, инстанцирующие объекты.
 

korchasa

LIMB infected
Автор оригинала: whirlwind
Тест, например контроллера зеленый, хотя должен валиться
ИМХО не стоит понимать интерфейс только как набор методов. Интерфейс это имя контракта класса. И TupleResultSet может имплементировать IResultSet, только если им можно заменить любой другой объект, имплементирующий IResultSet. Ну кроме случаев, когда клиент использует что-то за пределами IResultSet. В этом случае по идее надо делать не instanceof IResultSet, а instanceof ObjectResultSet.
 

fixxxer

К.О.
Партнер клуба
>> чем это поможет

само по себе ничем, но никто не ограничивает в наборе проверок.

вот, кстати, задумался о том, чтобы проверять через reflection набор реализуемых интерфейсов. на всякий.
 

whirlwind

TDD infected, paranoid
korchasa так вот как раз тут и есть проблема с return type. Если у IResultSet есть get без return type, то невозможно ограничить субтип конкретным результатом. Даже если можно, то это не всегда практично. Все что может быть нарушено, будет нарушено. Об этом нам говорят практически все языки со статической типизацией, которые подразумевают type casting.
 

HraKK

Мудак
Команда форума
Очередной вопрос:
Как протестировать Singleton'ы?
Ведь их нельзя создать новый, а в процессе тестов их состояние меняется, что мешает полноценно их оттестировать.

Пока ввел такое понятие как

PHP:
public static function endInstance()
{
     self::$instance = null;
}
А по другому, как то можно?
 

korchasa

LIMB infected
HraKK
Так удобнее. И гибче
PHP:
public static function setInstance($instance) 
{ 
     self::$instance = $instance; 
}
 

fixxxer

К.О.
Партнер клуба
На самом деле, синглтоны лучше просто не использовать. :)

Вот увидишь, как тебе в каком-нибудь крон-скрипте понадобится.. ну, почту разослать, например - и у тебя этот setInstance заюзается внутри foreach(). :)

Разве что-то совсем такое-эдакое, например Debugger.
 

HraKK

Мудак
Команда форума
Синглетон у меня пока аж 2 класса, первичные настройки ( и то думаю переписать), и главный класс приложения)

Не люблю синглетоны, они как-то в мое представление об ООП плохо ложатся.

-~{}~ 03.02.10 20:19:

Надо ли тестировать:

PHP:
public function some( Some_Interface $Some )
{
}
На выброс php ошибки при вхождении туда класса не того интерфейса?
 

whirlwind

TDD infected, paranoid
HraKK не надо. Именно по этому я за строгость языка. Строже язык - меньше работы. Скоро ты поймешь, что писать тесты легко и полезно. Проблема будет в своевременной остановке :)
 

HraKK

Мудак
Команда форума
Делаю мок какого-то обьекта потом вставляю в другой тестируемый объект, но в нем же стоит тайпхиттинг и он не проходит:
Argument 1 passed to Core_Application::setInstance() must implement interface Core_Application_Interface, instance of PHPUnit_Framework_MockObject_Builder_InvocationMocker given

Как же тогда тестировать? И почему мок не имплементирует оригинальные интерфейсы?
 

whirlwind

TDD infected, paranoid
Скорее всего просто не приинклюдился файл. Мок можно сделать даже на stdClass с любыми методами.
 

HraKK

Мудак
Команда форума
да нет, проинклудил. Вот код:
PHP:
new Core_Application(); // для теста что проинклудил
        $MockApplication = $this->getMock( 'Core_Application', array( 'getResource' ) )
			->expects( $this->any() )
            ->method( 'getResource' )
            ->will( $this->returnValue( $MockResource ) );
		$Application = Core_Application::setInstance( $MockApplication );
Выдает
PHP:
Argument 1 passed to Core_Application::setInstance() must implement interface Core_Application_Interface, instance of PHPUnit_Framework_MockObject_Builder_InvocationMocker
 
Сверху