Как мне создать фиктивный объект, который использует массив черт? - PullRequest
0 голосов
/ 30 августа 2018

Я сейчас нахожусь на PHPUnit v5.7.27

Я хотел бы создать фиктивный объект, который использует массив черт. Как бы я пошел по этому поводу? Я вижу только getMockForTrait как способ создания фиктивного объекта, используя одну черту. Моя проблема в том, что эта черта требует наличия другой черты на уровне класса.

Обновление: больше контекста к проблеме

Дано:

trait GetSet {
    public function __call(){ /* does some magic */
}

trait RepositoryAware {
    public function getRepository(string $name)
    {
        /* makes use of the GetSetTrait*/
    }
}

class Controller
{
    use GetSet;
    use RepositoryAware;
}

Учитывая ограничения PHP, я не могу просто поместить use GetSet в черту RepositoryAware, потому что другие черты, которые импортирует контроллер, также могут принести черту GetSet. Более того, сам класс контроллера может использовать поведение, предусмотренное чертой GetSet.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Концепция Mocking была построена с мыслью, что вы будете использовать внедрение зависимостей. Я, конечно, могу понять, почему вы можете не захотеть использовать внедрение зависимостей с таким множественным наследованием, как модель, которую использует php под названием «Черты». Инструменты-насмешки, подобные тем, что были созданы для phpunit, были созданы для замены экземпляров объектов, а не самих классов / интерфейсов / признаков. PHP Traits больше похожи на статическую зависимость, а не зависимость от экземпляра объекта. Однако, даже если вы использовали черты и предполагали, что черта в основном совпадает с классом, в соответствии с насмешливыми рекомендациями следует проверять черту как ее собственный тест, а не проверять черту через другой класс. Если вы хотите смоделировать саму черту, вы можете попытаться пересмотреть свой дизайн, поскольку я не верю, что это можно сделать. Вы, конечно, можете смоделировать черту и протестировать эту черту, но вы не можете смоделировать черту, а затем внедрить ее как зависимость от объекта. Представьте себе, что класс, например, реализует интерфейс, насмешка над чертой была бы такой же, как насмешка над интерфейсом, которую реализует класс, это невозможно. Вы можете только смоделировать интерфейс объекта, от которого зависит класс, путем внедрения зависимостей на основе сеттера или конструктора. Другим примером может быть попытка смоделировать класс, от которого наследуется тестируемый класс. Вы тоже не можете этого сделать. Возможно, в мире javascript этот тип вещей может быть полезен и с точки зрения некоторых людей желателен, но я думаю, что если вы хотите использовать насмешку, вам нужно придерживаться object внедрения зависимостей вместо статических use черт.

Так в чем же альтернатива? Я думаю, что следующий пример будет о том, как использовать, возможно, «традиционные» методы ООП с насмешками, чтобы достичь своей цели - поделиться функциональностью без использования наследования. Этот пример также делает ваши зависимости более явными. И, к сведению, я приветствую вас за то, что вы НЕ используете наследство.

<?php

interface GetterSetter {
    public function __call();
}

interface RepositoryProvider {
    public function getRepository(string $name);
}

class GetSet implements GetterSetter {

    public function __call() {
        /* does some magic */
    }
}

class DefaultRepository implements RepositoryProvider, GetterSetter {

    /**
     * @var GetterSetter
     */
    private $_getterSetter;

    public function __construct(GetterSetter $getterSetter) {
        $this->_getterSetter = $getterSetter;
    }

    public function getRepository(string $name) {
        // makes use of the GetSetTrait
        $this->__call();
    }

    public function __call() {
        // makes use of the GetSetTrait
        $this->_getterSetter->__call();
    }
}

class Controller implements RepositoryProvider, GetterSetter {

    /**
     * @var RepositoryProvider
     */
    private $repositoryProvider;

    public function __construct() {
        $this->repositoryProvider = new DefaultRepository(new GetSet());
    }

    public function getRepository(string $name) {
        return $this->repositoryProvider->getRepository($name);
    }

    public function __call() {
        $this->repositoryProvider->__call();
    }
}

В целом я чувствую, что сообщество PHP пошло на дикий левый поворот, пытаясь больше походить на javascript, и я чувствую, что черты могут загнать вас в угол. Это очень хороший пример такого угла. Я бы действительно избегал их, по крайней мере сейчас. В долгосрочной перспективе я считаю, что Generics будет лучшим решением вашей проблемы, связанной с необходимостью генерировать кусок кода GetSet, но в php еще не реализованы генерики :-(.

0 голосов
/ 30 августа 2018

Текущее решение, которое у меня есть, - создать Dummy Class, который импортирует и черты, и вместо этого имитирует этот класс:

class RepositoryAwareClass
{
    use GetSet;
    use RepositoryAware;
}

Таким образом, я могу правильно проверить поведение, обеспечиваемое чертой RepositoryAware, и в то же время составить ее требование черты GetSet.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...