我正在尝试嘲笑 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
我相信为什么这不起作用的问题是因为
Log::channel
在部分模拟上返回一个通道。因此,模拟实例永远不会收到错误调用。
在
Mockery
中,您可以通过在 shouldReceive()
调用中使用“->”轻松进行链式调用。
Log::shouldReceive('channel->error')
->once()
->andReturn(null);
我今天想到的答案是:
<?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')
。