Создание метода макета и заглушки, который возвращает self-макет

#php #unit-testing #mocking #phpunit #codeception

#php #модульное тестирование #издевательство #phpunit #codeception

Вопрос:

У меня есть класс следующим образом:

 class Foo extends BaseObject {

    public static function grab() {
        // do some DB search and return an instance of self
        // with the data in the object
        return new Foo($id);
    }

    public function insert() {
        // insert the data in the database for this object
        return false;
    }

    public function delete() {
        // delete the data from the database for this object
        return false;
    }

}
  

Как я могу издеваться над этим объектом, сохраняя при этом возможность утверждать, что вызовы insert и delete ведут себя так, как ожидалось?

Что я сделал, так это: use AspectMockTest;

     $mock = Test::double('Foo', [
        'grab' => Stub::make('Foo'),
        'insert' => true,
        'delete' => true,
    ]);

    // ... later in the test ...

    self::assertSame($foo->insert(), true);

    $mock->verifyInvoked('insert', 1);
  

Это обходит макет для методов insert and и update возвращает false вместо ожидаемого true . Он также не учитывает вызовы, как ожидалось.

Итак, как я могу заставить макет вернуть себя?

(Пожалуйста, простите за любую путаницу между mock и stub , которую я, возможно, допустил)

Ответ №1:

Я предлагаю вам использовать Phake для моделирования статического метода, как описано здесь в документе, в качестве примера:

 public function testInsert()
{
    /** @var AppFoo $classUnderTest */
    $classUnderTest = $this->getMockBuilder(Foo::class)
        ->disableOriginalConstructor()
        ->onlyMethods(['insert'])
        ->getMock();

    $classUnderTest->expects($this->once())
        ->method('insert')
        ->willReturn(true);

    /** @var AppFoo $fooGrab */
    $fooGrab = Phake::mock(Foo::class);
    Phake::whenStatic($fooGrab)
        ->grab()
        ->thenReturn($classUnderTest);

    $mock = $fooGrab::grab();

    $this->assertTrue($mock->insert());
}
  

Комментарии:

1. Я надеялся, что смогу сделать это без импорта другого целого пакета, просто чтобы пройти этот тест.

2. @Benjam Я понимаю, но PHPUnit не поддерживает статический макет и, похоже, Codeception тоже. В какой среде тестирования вы на самом деле участвуете в этом проекте?

3. AspectMock также доступен как часть этого пакета. Мы используем Codeception, который использует PHPUnit в качестве основы.