【问题标题】:Abstract method not getting mocked抽象方法没有被嘲笑
【发布时间】:2020-07-21 01:35:38
【问题描述】:

我有一个类似于这个简化示例的设置(应该通过直接复制粘贴来工作),但是我想模拟 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 驱动程序不再适用于我的本地 VM(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.

正如您从第二次调试打印中看到的 - Setting ACTUAL model of controller - 完全忽略了模拟。也不会出现错误或警告。模拟设置有什么问题?

我也尝试过使用overloadalias,但它们不起作用,即使使用:

/**
 * @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

【问题讨论】:

    标签: php unit-testing mockery


    【解决方案1】:

    我认为您无法按照自己的方式设置模拟。当您调用 ->makePartial() 或 ->make 或 ->getMockForAbstractClass() 时,将调用构造方法。所以 $this->setModel();总是返回 null。

    我会建议这个解决方案。

    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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-23
      • 2018-12-24
      相关资源
      最近更新 更多