PHPUnit - Дразнить черту
У меня есть черта, которая используется несколькими классами, т.е.
class SomeClass
{
use TimeoutTrait;
function handle() {
$this->traitFunction() // can this be mocked?
}
}
Модуль PHP способен издеваться над traitFunction()?.
Заранее спасибо за помощь.
Привет
3 ответа
Черты - это контейнеры кода, код которых "копируется" компилятором в класс, в котором вы хотите его использовать, что позволяет использовать его во всем мире.
Как правило, в модульных тестах нет ничего особенного с функциями черт. когда в классе создается экземпляр функции trait, функции не имеют никакого отличия от функций, которые могут быть вставлены при копировании, если они написаны в trait внутри вашего класса.
Так что не стесняйтесь смоделировать вашу функцию-черту так же, как любую другую обычную функцию, определенную внутри класса.
Когда вы макетируете класс с помощью PHPUnit, он расширяет класс и переопределяет методы, которые вы насмехаетесь, с заменой. Так что в вашем случае это будет выглядеть так:
$sut = $this->getMockBuilder('SomeClass')
->setMethods(['traitFunction'])
->getMock();
$sut->expects($this->once())
->method('traitFunction');
$sut->handle();
Хотя делать это не очень хорошая идея, ИМО. Вы указываете, как ваш класс должен что-то делать, а не то, что он должен делать. Если метод, который обеспечивает ваша черта, достаточно сложен, чтобы гарантировать свой собственный класс, то вы чувствуете, что вам нужно его высмеивать. Сделайте это отдельным классом и используйте шаблон стратегии для передачи поведения.
Ваш класс хотел бы это:
Class SomeClass {
private $handler;
public function __construct(ClassFormerlyATrait $handler) {
$this->handler = $handler;
}
public function handler() {
$this->handler->traitFunction();
}
}
Class ClassFormerlyATrait {
public function traitFunction() {
// Does whatever the trait did.
}
}
Это делает ваш дизайн немного сложнее, но теперь вы можете адаптировать свой класс к изменениям. Например, вам нужно traitFunction
делать что-то немного другое при определенных обстоятельствах. Вы бы расширили ClassFormerlyATrait новой функциональностью и вместо этого передали его SomeClass, не беспокоясь о нарушении любой существующей функциональности.
Самый простой способ - смоделировать родительский класс, а затем выполнить свои модульные тесты на эту черту. Или вы можете создать специальный класс для реализации черты, исключительно для модульного тестирования, но это предполагает, что ваша черта не делает ничего, что взаимодействует с родителем или наоборот.