如何Mock并测试服务中指定方法调用,忽略其他调用
Laravel Mock静态日志类:验证指定调用并忽略其他调用
现有代码
日志类 LogHelper
class LogHelper { public static function log(string $type, string $message, array $context = []): void { Log::channel('test')->{$type}($message, $context); } }
服务中的调用示例
$test->log('notice', 'test1234', ['1111' => '2222']); $test->log('notice', 'test5678', ['3333' => '4444']);
需求
Mock LogHelper类,验证程序是否执行了指定调用:
$test->log('notice', 'test1234', ['1111' => '2222']);
同时忽略该方法的其他所有调用(比如上述示例中的第二条调用)。
当前尝试的问题
以下代码仅在仅存在指定调用时有效,一旦有其他log调用,测试会直接失败:
$this->mock( LogHelper::class, function (MockInterface $mock) { $mock ->shouldReceive('log') ->withArgs(function ($type, $name, $context) { $this->assertSame('notice', $type); $this->assertSame('test1234', $name); $this->assertSame(['1111' => '2222'], $context); return true; }); } );
验收标准
测试通过(断言为true)的场景
- 包含指定调用和两个无关调用:
$test->log('notice', 'test', ['test' => 'test']); $test->log('notice', 'test1234', ['1111' => '2222']); $test->log('notice', 'test5678', ['3333' => '4444']);
- 包含指定调用和一个无关调用:
$test->log('notice', 'test1234', ['1111' => '2222']); $test->log('notice', 'test5678', ['3333' => '4444']);
- 包含指定调用和另一个无关调用:
$test->log('notice', 'test', ['test' => 'test']); $test->log('notice', 'test1234', ['1111' => '2222']);
- 仅包含指定调用:
$test->log('notice', 'test1234', ['1111' => '2222']);
测试失败(断言为false)的场景
- 程序从未执行过指定的
log('notice', 'test1234', ['1111' => '2222'])调用
解决方案
修改Mock逻辑,先断言指定调用至少执行一次,再允许其他任意log调用无限制执行:
$this->mock(LogHelper::class, function (MockInterface $mock) { // 验证指定的log调用至少执行一次 $mock->shouldReceive('log') ->with('notice', 'test1234', ['1111' => '2222']) ->atLeast()->once(); // 允许所有其他log调用,不进行断言 $mock->shouldReceive('log') ->withAnyArgs() ->andReturn(); });
方案说明
->with('notice', 'test1234', ['1111' => '2222']):精准匹配需要验证的调用参数->atLeast()->once():确保指定调用至少执行一次,覆盖所有测试通过场景->withAnyArgs():匹配所有其他log调用,andReturn()让这些调用无副作用执行,不会触发断言失败
内容的提问来源于stack exchange,提问作者fico7489
相关产品推荐
相关产品推荐

