无法在 Laravel 中模拟部分 Log 门面

问题描述 投票:0回答:2

我正在尝试嘲笑 laravel

Log
。这是我的代码:

public function test_process_verify_card()
{
    Log::shouldReceive('error')->once();
    Log::makePartial();
    $class = new MyClass();
    $class->myFunction();
}

这是

MyClass
看起来像:

class MyClass
{
    public function __construct()
    {
        $this->logger = Logg::channel('test');
    }

    public function myFunction()
    {
        // ... some logic
        $this->loggger->error('Errror!!');
    }
}

当我运行测试这个测试用例时,它抛出错误

Call to a member function runningUnitTests() on null

  at vendor/laravel/framework/src/Illuminate/Log/LogManager.php:568

我尝试通过将

dd()
放入
LogManager

来调试此错误
    protected function parseDriver($driver)
    {
        $driver ??= $this->getDefaultDriver();
        dd($this->app); // <--- This is my code
        if ($this->app->runningUnitTests()) {
            $driver ??= 'null';
        }

        return $driver;
    }

但它表明

$this->app
不是
null

我之前尝试过模拟外观

Date
,效果很好。

我想测试

myFunction
是否执行记录操作。这是正确的做法吗?

更新

我也尝试通过

partialMock()
函数来模拟它:

    public function test_process_verify_card()
    {
        $this->partialMock(Logger::class, function (MockInterface $mock) {
            $mock->shouldReceive('error')->once();
        });
        $class = new MyClass();
        $class->myFunction();
    }

但是还是不行,显示错误:

  Method error(<Any Arguments>) from Mockery_0_Illuminate_Log_Logger should be called
 exactly 1 times but called 0 times.

  at vendor/phpunit/phpunit/phpunit:98
php laravel testing mocking
2个回答
5
投票

我相信为什么这不起作用的问题是因为

Log::channel
在部分模拟上返回一个通道。因此,模拟实例永远不会收到错误调用。

Mockery
中,您可以通过在
shouldReceive()
调用中使用“->”轻松进行链式调用。

Log::shouldReceive('channel->error')
    ->once()
    ->andReturn(null);

0
投票

我今天想到的答案是:

<?php

namespace Tests\Utils;

use Illuminate\Log\LogManager;
use Illuminate\Support\Facades\Log;
use Mockery;

trait MocksLogger
{
    protected function mockLogger()
    {
        $logger = Mockery::mock(LogManager::class, [$this->app])->makePartial();
        Log::swap($logger);

        return $logger;
    }
}

...

use MocksLogger;
public function someTest() {
    $logger = $this->mockLogger();
    $logger->shouldReceive('info')->with('Some message');
}

基本上从

LogManager
类创建部分模拟(并且重要的是,将应用程序实例注入其中,而标准
Log::partialMock
shouldReceive
则不会这样做。这样,如果您正在使用其他一些记录器方法(例如在我的情况是我在某些提供程序中使用
logger()->driver()
)不会有异常,因为这个方法调用实际上不会被模拟,除非您在模拟实例上显式使用
shouldReceive('driver')

© www.soinside.com 2019 - 2024. All rights reserved.