- почему не mockery
- основное преимущество — синтаксис
- моки — нативные
- создание stub-объектов
- мокирование свойств класса
- mock injection
- удобные методы для работы с Reflection
- как добавить в проект
Почему не Mockery
PHPUnit — стандартный, наиболее распространенный фреймворк для написания unit-тестов в мире PHP. Ничего удивительного — он хорошо справляется с возложенными на него обязанностями. Но если говорить о стандартном синтаксисе создания mock-объектов, многие люди жалуются на его некоторую громоздкость. Они предлагают различные плагины для создания моков, такие как Mockery (я понимаю, что это не просто плагин).
Однако, я уверен что PHPUnit обладает достаточно хорошо развитой системой для создания моков, чтобы продолжать его использовать. PHPUnit активно развивается: не так давно были добавлены мокирование трейтов, мокирование несуществующих классов — для TDD.
И этот проект XPMock — это способ упростить синтаксис создания моков. Нужно подчеркнуть, что XPMock не создает собственные моки, и не делает никаких оберток над моками PHPUnit. XPMock вызывает те же самые методы PHPUnit, создавая тем самым те же самые моки, только несколько проще.
Основное преимущество — синтаксис
Стандартный синтаксис для создания мока (объекта-заглушки с тремя методами) в PHPUnit выглядит так:
$mock = $this->getMockBuilder('MyClass') ->setMethods(['getBool', 'getNumber', 'getString']) ->disableOriginalConstructor() ->getMock(); $mock->expects($this->any()) ->method('getBool') ->will($this->returnValue(true)); $mock->expects($this->any()) ->method('getNumber') ->will($this->returnValue(1)); $mock->expects($this->any()) ->method('getString') ->will($this->returnValue('string'));
Те, кто мокируют большую часть зависимостей в unit-тестах, замечают, что код теста очень быстро разрастается именно из-за таких конструкций.
Если же использовать XPMock, то создание мока становится значительно короче:
$this->mock('MyClass') ->getBool(true) ->getNumber(1) ->getString('string') ->new();
Моки — нативные
XPMock
— не создает свои собственные моки
— не делает дополнительных оберток над моками PHPUnit
— поддерживает все нативные конструкции PHPUnit
Например,
$mock->getNumber($this->once())
это то же самое, что написать
$mock->expects($this->once()) ->method('getNumber') ->will($this->returnValue(null))
Другие примеры короткой записи часто используемых конструкций можно посмотреть здесь: github.com/ptrofimov/xpmock
Создание stub-объектов
Stub-объекты, или объекты-заглушки, — это мок-объекты, у которых все методы по умолчанию перекрывают реальные методы и возвращают null. В PHPUnit в синтаксисе нет деления на моки, стабы и иже с ними. Все искусственные объекты для тестирования создаются с помощью getMock или getMockBuilder.
В XPMock включен специальный метод stub который вернет мок, у которого все методы по умолчанию возвращают null. Это и улучшает читаемость кода, и избавляет от необходимости вызывать метод setMethods при создании реальных моков.
Мокирование свойств класса
PHPUnit не умеет мокировать свойства класса. XPMock — тоже. Однако он предоставляет удобные методы задания свойств у создаваемого мока через Reflection. Указанные при создании мока присваивания будут выполнены сразу после вызова метода-конструктора new.
$this->mock(‘MyClass’) ->__set(‘property’, $value) ->new();
Можно использовать и привычный синтаксис задания свойств без использования магических методов.
Mock injection
Очень часто при создании моков их нужно сразу же внедрить в другие объекты. Например, создать instance синглтона и внедрить ссылку на него в статическую переменную instance того же класса. Обычно это делается через Reflection. XPMock и здесь предоставляет удобный синтаксис для таких действий.
$this->mock(‘MyClass’) ->injectTo($object, ‘property’) ->new();
Удобные методы для работы с Reflection
XPMock предоставляет и общий короткий синтаксис для работы с объектами через Reflection.
Например, чтобы получить закрытое свойство объекта, обычно нужно писать так:
$property = new \ReflectionProperty(‘MyClass’, ‘property’); $property->setAccessible(true); $value = $property->getValue($object);
С XPMock можно это делать так:
$value = $this->reflect('MyClass')->property;
Подобным синтаксисом можно получать значения закрытых/открытых статических/нестатических свойств объектов, а также вызывать закрытые методы.
Как добавить в проект
XPMock легко встраивается в существующие тесты и не мешает работать нативному синтаксису создания моков PHPUnit.
Вариант 1. Добавить трейт XPMock к существующему тесту (подходит для PHP>=5.4)
class MyTestCase extends \PHPUnit_Framework_TestCase { use \Xpmock\TestCaseTrait; }
Вариант 2. Унаследовать класс теста от соответстующего класса XPMock (подходит для PHP>=5.3)
class MyTestCase extends \Xpmock\TestCase { }
Добавить XPMock в проект очень просто — через менеджер зависимостей composer. Инструкция по установке из 2-х шагов здесь — github.com/ptrofimov/xpmock#installation
ссылка на оригинал статьи http://habrahabr.ru/post/183010/
Добавить комментарий