Как писать unit-тесты на конструктор

hell0w0rd

Продвинутый новичок
Допустим есть класс
PHP:
class Foo
{
    private $bar;

    public function __construct($bar)
    {
        $this->setBar($bar);
    }

    public function setBar($bar)
    {
        $this->bar = $bar;
    }

    public function getBar()
    {
        return $this->bar;
    }
}
Пишем тест на гет/сет:
PHP:
public function testBar()
{
    $foo = $this->createFoo();
    $foo->setBar('foo');

    $this->assertEquals('foo', $foo->getBar());
}
Теперь фактически мы должны протестировать, что конструктор реально вызовет setBar. Я тут понял, что не правильно это тестирую, потому что для проверки конструктора вызываю getBar.
По хорошему надо мокнуть, но примеры очень громоздкие: http://miljar.github.io/blog/2013/12/20/phpunit-testing-the-constructor/
Есть какой-то другой вариант? Как это делаете вы?
 

hell0w0rd

Продвинутый новичок
В комментах по ссылке есть.. но это какой-то ппц все равно.
PHP:
public function testConstructSetName()
{
    $mock = $this->getMockBuilder('Foo')->disableOriginalConstructor()->getMock();
    $mock->expects($this->once())->method('setBar')->with($this->equalTo('test'));
    $this->mock->__construct('test');
}
Может есть какая-то либа упрощающая подобные тесты, или другой подход?
 

Вурдалак

Продвинутый новичок
Я не вижу никакого смысла мокать собственные же методы тестируемого класса. Это нарушение инкапсуляции.

А если тебе всё-таки требуется мокать какой-то метод, то, вероятно, тут уже есть нарушение SRP.
 

hell0w0rd

Продвинутый новичок
Вурдалак, какое нарушение инкапусляции? У меня есть задача, проверить, что конструктор вызовет нужные сеттеры. В конструкторе могут быть условия, например $bar не обязателен ($bar = null) и если не null - вызывается сеттер.
 

AmdY

Пью пиво
Команда форума
hell0w0rd, а чем тебе вариант с disableOriginalConstructor не нравится, вроде всё логично, тестируется конструктор как и любой другой метод. Для обычных тестов лучше так же отключать конструктор, раз уж юнит тест, то тестить один метод, без конструктора, замоков остальные.

Хотя вариант Вурдалак, мне нравится, я бы тоже не мокал всё подрят, особенно геттеры-сеттеры.
 

Вурдалак

Продвинутый новичок
hell0w0rd, откуда ты знаешь, что конструктор вызывает какие-то сеттеры?

Или даже правильнее спросить: а нахрена у тебя стоит такая задача? Вызовет сеттер или запишет напрямую в свойство — тебя это волнует? Почему?
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Вурдалак, какое нарушение инкапусляции? У меня есть задача, проверить, что конструктор вызовет нужные сеттеры.
А нафига? Никого не должно волновать, что там внутри. Ну напишу я вместо вызова сеттера прямое присваивание, и что? Все точно так же хорошо будет работать.
 

hell0w0rd

Продвинутый новичок
fixxxer, да, я об этом тоже подумал. У нас тесты не должны зависить от реализации по идее.
То есть геттеры-сеттеры считаем простейшим кодом, который правильно работает по умолчанию?
 

Вурдалак

Продвинутый новичок
Чисто в теории, ты не можешь знать, без нарушения всё той же инкапсуляции, о том простые это методы или нет.

На практике их тестировать неразумно.

Но речь не о простоте: речь идёт о том, что ты не должен мокать собственные же методы класса.
 

fixxxer

К.О.
Партнер клуба
fixxxer, да, я об этом тоже подумал. У нас тесты не должны зависить от реализации по идее.
То есть геттеры-сеттеры считаем простейшим кодом, который правильно работает по умолчанию?
Вообще смысла это тестировать не вижу. Но если платят премию стопицотмильонов за coverage 100% - то точно так же, как и сеттер - проверять, что getBar() возвращает то, что сунули в конструктор.
 

fixxxer

К.О.
Партнер клуба
Но вообще если кругом пары геттер-сеттер, я бы не тесты писал, а задумался, в каком месте у меня нарушается tell don't ask.
 
Сверху