如何在其他 class 中模拟 class

How to mock class which within other class

Connect.php

class Connect
{
    private $dbName;

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

    public function getQuery()
    {
        return $this->dbName;
    }
}

ConnectFacade.php

class ConnectFacade
{
    public $dbA;
    public $dbB;
    public $dbC;
    public $dbD;

    public function __construct()
    {
        $this->dbA = new Connect('connect to database a');
        $this->dbB = new Connect('connect to database b');
        $this->dbC = new Connect('connect to database c');
        $this->dbD = new Connect('connect to database d');
    }
}

Member.php

class Member
{
    private $connect;

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

    public function data()
    {
        return $this->connect->dbA->getQuery();
    }
}

index.php

require 'vendor/autoload.php';

echo (new Member(new ConnectFacade))->data();

在我的例子中,我有许多来自许多数据库的表需要连接到一个 class,因此我需要经常声明许多具有不同连接名称的连接,所以我把它放在 ConnectFacade 为了节省时间,我知道这有点复杂,但这就是我公司的结构,这个示例代码将在 index.php 上显示 connect to database a,当然实际上连接正在做很多事情,我的问题是我不知道如何模拟这种情况,这是我试过的

use Mockery as m;

class MemberTest extends PHPUnit_Framework_TestCase
{
    public function testData()
    {
        $connect = m::mock('ConnectFacade');
        $connect->shouldReceive('dbA->getQuery')
            ->once()
            ->andReturn(true);
        $actual = (new Member($connect))->data();
        $this->assertTrue($actual);
    }

    public function tearDown()
    {
        m::close();
    }
}

得到了Call to a member function getQuery() on a non-object in D:\www\phpunit\class\Member.php on line 14,不知道怎么才能通过

问题是 dbA 不是 ConnectFacade 上的一个方法,而是一个变量。因此 $connect->shouldReceive('dbA->getQuery') 将不起作用。

相反,您需要将 dbA 变量设置为模拟,然后将期望更改为仅接收 getQuery:

public function testData()
{
    $connect = m::mock('ConnectFacade');
    $connect->dbA = $connect;
    $connect->shouldReceive('getQuery')
        ->once()
        ->andReturn(true);
    $actual = (new Member($connect))->data();
    $this->assertTrue($actual);
}

另一种选择是在 ConnectFacade 中模拟 Connect class 的创建,而不是模拟整个 ConnectFacade:

public function testData()
{
    $connect = m::mock('overload:Connect');
    $connect->shouldReceive('getQuery')
        ->once()
        ->andReturn(true);
    $connectFacade = new ConnectFacade;
    $actual = (new Member($connectFacade))->data();
    $this->assertTrue($actual);
}