Абстрактный метод не высмеивают - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть установка, похожая на этот упрощенный пример (должна работать, копируя ее напрямую), но метод, который я хочу смоделировать Controller->setModel(), не осмеивается. Также не отображаются ошибки:

<?php

use PHPUnit\Framework\TestCase;

// Implementation
class Model
{
    // The constructor here would receive a PDO, but that's not important
    public $data = [
        ['id' => 1, 'text' => 'nope'],
        ['id' => 2, 'text' => 'no'],
        ['id' => 3, 'text' => 'not']
    ];

    public function getItem($id)
    {
        // And here we would query with the PDO instead, but again
        // the question is more about mocking the setModel() method
        return $this->data[$id];
    }
}

abstract class Endpoint
{
    public function __construct()
    {
        echo "\n1. Calling abstract class constructor\n";
        $this->model = $this->setModel();
    }

    abstract protected function setModel();
}

class Controller extends Endpoint
{
    public function getStuff($id)
    {
        echo "3. Getting stuff from controller\n";
        $data = $this->model->getItem($id);
        return ['id' => $data['id'], 'text' => $data['text']];
    }

    protected function setModel()
    {
        echo "2. Setting ACTUAL model of controller\n";
        $config = 'sqlite:myfile.sqlite3'; // Suppose this file exists and is valid
        $pdo = new \PDO($config);
        return new Model($pdo);
    }
}

// Test
final class ControllerTest extends TestCase
{
    public function testExample()
    {
        $mockModel = \Mockery::mock('FakeModel')
            ->shouldReceive('getItem')
            ->andReturn(['id' => 123, 'text' => 'myCustomText']);

        $mock = \Mockery::mock('Controller')->makePartial()
            ->shouldAllowMockingProtectedMethods();
        $mock->shouldReceive('setModel')->andReturn($mockModel);

        $controller = new Controller();
        $result = $controller->getStuff(2);
        $this->assertEquals('myCustomText', $result['text']);
    }
}

Результат теста следующий. Исключение PDOException связано с тем, что драйвер php5 -sqlite больше не доступен для моей локальной виртуальной машины (Ubuntu 18.04). Я использую Docker образ для установки, но та же проблема с поддельными происходит и в этом тоже. Но не в этом суть - дело в том, чтобы высмеивать setModel():

1. Calling abstract class constructor
2. Setting ACTUAL model of controller


Time: 110 ms, Memory: 7.25MB

There was 1 error:

1) ControllerTest::testExample
PDOException: could not find driver

/home/juha/koodaus/pastes/backend/test/Foo/FooTest.php:45
/home/juha/koodaus/pastes/backend/test/Foo/FooTest.php:26
/home/juha/koodaus/pastes/backend/test/Foo/FooTest.php:63

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

Как вы можете видеть из 2-го отладочного отчета - Setting ACTUAL model of controller - макет полностью игнорируется. Никаких ошибок или предупреждений не появляется. Что не так с настройкой макета?

Я также пытался с overload и alias, но они не работают, даже с:

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */

В результате:

Mockery\Exception\RuntimeException: Could not load mock Controller, class already exists

Но я думаю, что это известная проблема.

Версии (устаревшая настройка, которая не поддерживает PHP 7):

PHP 5.6.40
PHPUnit 5.7.27
Насмешка 1.3.1

1 Ответ

0 голосов
/ 24 апреля 2020

Я не думаю, что вы можете настроить свой макет так, как вы хотите. Метод конструкции вызывается, когда вы вызываете -> makePartial () или -> make или -> getMockForAbstractClass (). поэтому $ this-> setModel (); всегда возвращает нуль.

Я бы предложил это решение.

public function testExample()
{

    $mock = $this->getMockBuilder(Controller::class)
            ->setMethods(['setModel'])->getMock();

    $mockModel = \Mockery::mock('FakeModel');
    $mockModel->shouldReceive('getItem')
            ->andReturn(['id' => 123, 'text' => 'myCustomText']);

    $mock->method('setModel')->willReturn($mockModel);

    $mock->instuctModel();

    $result = $mock->getStuff(2);
    $this->assertEquals('myCustomText', $result['text']);
}

И класс EndPoint Abstract должен измениться на следующий

abstract class Endpoint
{
    protected $model;

    public function __construct()
    {
        echo "\n1. Calling abstract class constructor\n";
    }

    public function instuctModel(){

        $this->model = $this->setModel();
    }

    abstract public function setModel();
}
...