PHPUnit: заглушка нескольких интерфейсов - PullRequest
7 голосов
/ 17 декабря 2011

Я разбираюсь с PHPUnit и до сих пор находил его довольно простым в использовании, но я столкнулся с тестовым примером, который вызывает у меня трудности.

Я пишу код для набора интерфейсов, которые должны реализовать объекты (некоторые из них PHP, некоторые самостоятельно), а SUT требует входной объект для реализации нескольких интерфейсов. Например:

class MyClass implements ArrayAccess, MyInterface
{
    // ...
}

SUT делает такую ​​вещь:

class ClassToBeTested
{
    protected $obj = NULL;

    public function __construct ($obj)
    {
        $this -> obj = $obj;
    }

    public function methodToBeTested ()
    {
        if ($this -> obj instanceof ArrayAccess)
        && ($this -> obj instanceof MyInterface)
        {
            // ...
        }
    }

    public function otherMethodUnderTest ()
    {
        if ($this -> obj instanceof ArrayAccess)
        {
            // ...
        }
        else
        if ($this -> obj instanceof MyInterface)
        {
            // ...
        }
    }
}

Я могу создать заглушку из одного или другого интерфейса, но я не знаю, можете ли вы создать заглушку, которая реализует их оба.

protected function setUp ()
{
    $stubField  = $this -> getMockBuilder ('ArrayAccess')
            -> getMock ();
    $this -> object = new ClassToBeTested ($stubField);
}

или

protected function setUp ()
{
    $stubField  = $this -> getMockBuilder ('MyInterface')
            -> getMock ();
    $this -> object = new ClassToBeTested ($stubField);
}

Можно ли генерировать заглушки из списка интерфейсов или мне нужно заглушить конкретный класс, который реализует ожидаемые интерфейсы? Это само по себе вызывает трудности, потому что самому классу, который нужно пометить, нужен другой объект, который нужно передать его конструктору, и я не могу заставить работать либо disableOriginalConstructor (), либо setConstructorArgs (). рассматриваемые конкретные классы не реализуют конструктор сами, а наследуют его от суперкласса. Я что-то упускаю здесь очевидное?

Ответы [ 3 ]

6 голосов
/ 17 декабря 2011

У вас есть доступ к редактированию исходного кода? Если это так, я бы создал новый интерфейс, который расширяет как ArrayAccess, так и MyInterface. Таким образом, вы должны иметь возможность заглушить / смоделировать объект для проверки тестируемого метода.

4 голосов
/ 31 марта 2018

На будущее, если кто-то увидит этот ответ, это работает для меня в PHPUnit 7:

$mock = $this
  ->getMockBuilder([InterfaceA::class,InterfaceB::class])
  ->getMock();
2 голосов
/ 02 апреля 2013

Не стоит создавать интерфейс в базе кода приложения для радости тестов . Я имею в виду, что вы можете создать этот интерфейс, но было бы лучше, если бы вы поместили его где-нибудь в базе тестового кода. Например, вы можете поместить интерфейс после класса теста в файл напрямую

Чтобы протестировать два интерфейса одновременно, я создал интерфейс в файле тестового примера (это может быть любое другое место)

interface ApiAwareAction implements ActionInterface, ApiAwareInterface
{
}

И после того, как я издевался над этим классом:

$this->getMock('Payum\Tests\ApiAwareAction');
...