2015-05-26 3 views
0

У меня есть класс, который идет что-то вроде следующего:Тестирование Использование класса Необязательно В Project

class Foo { 

    /** 
    * @var array|Bar 
    */ 
    protected $source; 

    public function __construct($source = []) { 
    if (class_exists(Bar::class)) { 
     $source = new Bar($source); 
    } 

    $this->source = $source; 
    } 

    public function getSource() { 
    return $this->source; 
    } 

    // ... 

} 

Bar приходит из отдельного PHP пакета, необязательной зависимости перечисленных в разделе suggestcomposer.json.

Я хочу написать два отдельных ожидания в phpspec для getSource()

function it_provides_array_source_by_default() { 
    $this->getSource()->shouldBeArray(); 
} 

function it_provides_bar_instance_when_available() { 
    $this->getSource()->shouldReturnAnInstanceOf(Bar::class); 
} 

Я не могу протестировать shouldBeArray(), если мой require-dev для пакета включает в себя зависимость, содержащую Bar.

Я не могу издеваться Bar как:

function it_provides_bar_instance_when_available(Bar $bar) { 
    $this->getSource()->shouldReturnAnInstanceOf(Bar::class); 
} 

, потому что я получаю сообщение об ошибке: phpspec

[PhpSpec\Exception\Locator\ResourceCreationException] Can not find appropriate suite scope for class Bar .

Что является метод наилучшей практики для проверки возвращаемого значения является необязательным классом как это?

ответ

1

Переместить логику, которая выбирает тип $source во внешнюю заводскую функцию.

class Foo { 

    protected $source; 

    public function __construct($source = []) { 
    $this->source = $source; 
    } 

} 

class FooFactory { 

    public get() { 
    $source = []; 
    if (class_exists(Bar::class)) { 
     $source = new Bar($source); 
    } 

    return new Foo($source); 
    } 

} 

Это позволяет явно проверить Foo оба пути и разъединяет реализации, перемещая все для модели зависимостей впрыскивается.

+0

Спасибо за это. Я бы предпочел избежать фабрики для моей конкретной реализации. Я полагаю, что у меня может быть некоторый 'AbstractFoo', поскольку у вас есть' Foo' в вашем ответе * (напрямую работая с источником массива) *, и у меня есть Foo extends AbstractFoo' с моей проверкой реализации для 'Bar'. Я мог бы заглушить 'AbstractFoo' для тестов массива и использовать' Foo' непосредственно для тестов 'Bar'. Даже при этом, однако, неправильно формулировать класс * просто * для тестирования. – deefour

+0

Это действительно портит меня не так, как у вас есть «Бар», жестко запрограммированный в вашем конструкторе. Только для этого вы должны переместить его на завод. – deceze

+0

Еще раз спасибо. Хотя тестирование фабрик с phpspec связано с его собственным набором трудностей, я думаю, что я все настроен сейчас. – deefour