繁体   English   中英

Laravel 7 部分模拟 eloquent model 因 __construct() 而失败,但未指定预期

[英]Laravel 7 partial mock eloquent model fails with __construct(), but no expectations were specified

我正在使用 Laravel 7 并尝试部分模拟 eloquent model ..

我的 controller 注入了 eloquent model 依赖项:

use App\Models\Ticket;

class TicketsController extends Controller
{
    /** @var Ticket */
    private $tickets;

    public function __construct(Ticket $ticket) {
        $this->tickets = $ticket;
    }

    public function get() {
        $tickets = $this->tickets::whereNull('staff_id')
            ->where('status', '!=', $this->tickets::STATUS_CLOSED)
            ->orderBy('created_at', 'desc')
            ->get();
    }
}

单元测试:

use App\Models\Ticket;

    $this->partialMock(Ticket::class, function($mock) {
        $mock->shouldReceive('get')
            ->once()
            ->andReturn([]);
    });

    $response = $this->json('get', route('tickets'));

    $response->assertOk();

失败:

testing.ERROR:收到 Mockery_0_App_Models_Ticket::__construct(),但未指定预期 {"exception":"[object] (Mockery\Exception\BadMethodCallException(code: 0): Received Mockery_0_App_Models_Ticket::__construct(),但没有预期在 /opt/project/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) 指定:eval()'d code:911)

还尝试为此更改测试:

    $ticketsMock = Mockery::mock(Ticket::class);
    $ticketsMock
        ->makePartial()
        ->shouldReceive('get')
        ->once()
        ->andReturn([]);

    $this->instance(Ticket::class, $ticketsMock);

但得到完全相同的错误..

如果我将模拟替换为非部分模拟并伪造 model 上的所有方法调用,它工作正常。但是一些 eloquent 查询会很长,我试图通过部分模拟完成它,所以我不必伪造每个单链调用,例如->shouldReceive('something')->andReturnSelf()

partial 的问题在于whereNull返回的是QueryBuilder而不是 Ticket model。

我认为一个好的解决方案是 mocking demeter 链 您可以通过在字符串whereNull->where->orderBy->get中进行表达来模拟流畅的调用。 我得到了以下示例以在本地工作。

$this->mock(Ticket::class, function($mock) {
    $mock->shouldReceive('whereNull->where->orderBy->get')
        ->once()
        ->andReturn([]);
});

您仍然必须表达模拟调用的路径,但我认为这是非常合理和直接的,因为您不必考虑参数和返回。

我稍微更改了 controller 方法,因为您在对象上静态调用了方法。 为了确保它正常工作,我的 controller 逻辑是这样的。

$tickets = $this->tickets->whereNull('staff_id')
    ->where('status', '!=', Ticket::STATUS_CLOSED)
    ->orderBy('created_at', 'desc')
    ->get();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM