timacdonald / log-fake
Laravel 框架测试的伪日志器。
Requires
- php: ^8.1
- illuminate/collections: ^10.0 || ^11.0
- illuminate/contracts: ^10.0 || ^11.0
- illuminate/log: ^10.0 || ^11.0
- illuminate/support: ^10.0 || ^11.0
- phpunit/phpunit: ^10.0 || ^11.0
- psr/log: ^1.0 || ^2.0 || ^3.0
- symfony/var-dumper: ^6.0 || ^7.0
Requires (Dev)
- illuminate/config: ^10.0 || ^11.0
- illuminate/container: ^10.0 || ^11.0
- timacdonald/callable-fake: ^1.0
README
Laravel 伪日志器
许多 Laravel 门面和服务可以伪造,例如使用 Bus::fake()
的调度器,以帮助测试和断言。此包允许您伪造应用程序中的日志记录器,并包括针对通道、堆栈等进行的断言的能力。
安装
您可以使用 composer 安装。
composer require timacdonald/log-fake --dev
基本用法
use Illuminate\Support\Facades\Log; use TiMacDonald\Log\LogEntry; use TiMacDonald\Log\LogFake; public function testItLogsWhenAUserAuthenticates() { /* * Test setup. * * In the setup of your tests, you can call the following `bind` helper, * which will switch out the underlying log driver with the fake. */ LogFake::bind(); /* * Application implementation. * * In your application's implementation, you then utilise the logger, as you * normally would. */ Log::info('User logged in.', ['user_id' => $user->id]); /* * Test assertions. * * Finally you can make assertions against the log channels, stacks, etc. to * ensure the expected logging occurred in your implementation. */ Log::assertLogged(fn (LogEntry $log) => $log->level === 'info' && $log->message === 'User logged in.' && $log->context === ['user_id' => 5] ); }
通道
如果您在应用程序中向特定通道(即非默认通道)记录日志,则需要以相同方式对断言进行前缀。
public function testItLogsWhenAUserAuthenticates() { // setup... LogFake::bind(); // implementation... Log::channel('slack')->info('User logged in.', ['user_id' => $user->id]); // assertions... Log::channel('slack')->assertLogged( fn (LogEntry $log) => $log->message === 'User logged in.' ); }
堆栈
如果您在应用程序中向堆栈记录日志,就像通道一样,您需要为断言添加前缀。请注意,堆栈的顺序无关紧要。
public function testItLogsWhenAUserAuthenticates() { // setup... LogFake::bind(); // implementation... Log::stack(['stderr', 'single'])->info('User logged in.', ['user_id' => $user->id]); // assertions... Log::stack(['stderr', 'single'])->assertLogged( fn (LogEntry $log) => $log->message === 'User logged in.' ); }
就是这样。现在让我们深入了解可用的断言,以提高您测试应用程序日志记录的体验。
可用的断言
请记住,所有断言都与上面显示的通道或堆栈相关。
assertLogged()
assertLoggedTimes()
assertNotLogged()
assertNothingLogged()
assertWasForgotten()
assertWasForgottenTimes()
assertWasNotForgotten()
assertChannelIsCurrentlyForgotten()
assertCurrentContext()
assertLogged()
断言已创建日志。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::info('User logged in.'); /* * assertions... */ Log::assertLogged( fn (LogEntry $log) => $log->message === 'User logged in.' ); // ✅ Log::assertLogged( fn (LogEntry $log) => $log->level === 'critical' ); // ❌ as log had a level of `info`.
assertLoggedTimes()
断言日志创建特定次数。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::info('Stripe request initiated.'); Log::info('Stripe request initiated.'); /* * assertions... */ Log::assertLoggedTimes( fn (LogEntry $log) => $log->message === 'Stripe request initiated.', 2 ); // ✅ Log::assertLoggedTimes( fn (LogEntry $log) => $log->message === 'Stripe request initiated.', 99 ); // ❌ as the log was created twice, not 99 times.
assertNotLogged()
断言日志从未创建。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::info('User logged in.'); /* * assertions... */ Log::assertNotLogged( fn (LogEntry $log) => $log->level === 'critical' ); // ✅ Log::assertNotLogged( fn (LogEntry $log) => $log->level === 'info' ); // ❌ as the level was `info`.
assertNothingLogged()
断言未创建任何日志。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::channel('single')->info('User logged in.'); /* * assertions... */ Log::channel('stderr')->assertNothingLogged(); // ✅ Log::channel('single')->assertNothingLogged(); // ❌ as a log was created in the `single` channel.
assertWasForgotten()
断言通道至少被遗忘一次。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::channel('single')->info('User logged in.'); Log::forgetChannel('single'); /* * assertions... */ Log::channel('single')->assertWasForgotten(); // ✅ Log::channel('stderr')->assertWasForgotten(); // ❌ as it was the `single` not the `stderr` channel that was not forgotten.
assertWasForgottenTimes()
断言通道被遗忘特定次数。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::channel('single')->info('User logged in.'); Log::forgetChannel('single'); Log::channel('single')->info('User logged in.'); Log::forgetChannel('single'); /* * assertions... */ Log::channel('single')->assertWasForgottenTimes(2); // ✅ Log::channel('single')->assertWasForgottenTimes(99); // ❌ as the channel was forgotten twice, not 99 times.
assertWasNotForgotten()
断言通道未被遗忘。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::channel('single')->info('User logged in.'); /* * assertions... */ Log::channel('single')->assertWasNotForgotten(); // ✅
assertChannelIsCurrentlyForgotten()
断言通道目前已被遗忘。这与断言通道已经被遗忘不同。
可以在以下位置调用
- 门面基础
(默认通道) - 通道
- 堆栈
示例测试
/* * implementation... */ Log::channel('single')->info('xxxx'); Log::forgetChannel('single'); /* * assertions... */ Log::assertChannelIsCurrentlyForgotten('single'); // ✅ Log::assertChannelIsCurrentlyForgotten('stderr'); // ❌ as the `single` channel was forgotten, not the `stderr` channel.
assertCurrentContext()
断言通道目前具有指定的上下文。您可以将预期的上下文作为数组提供,或者您可以提供真值测试闭包以检查当前上下文。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::withContext([ 'app' => 'Acme CRM', ]); Log::withContext([ 'env' => 'production', ]); /* * assertions... */ Log::assertCurrentContext([ 'app' => 'Acme CRM', 'env' => 'production', ]); // ✅ Log::assertCurrentContext( fn (array $context) => $context['app'] === 'Acme CRM') ); // ✅ Log::assertCurrentContext([ 'env' => 'production', ]); // ❌ missing the "app" key. Log::assertCurrentContext( fn (array $context) => $context['env'] === 'develop') ); // ❌ the 'env' key is set to "production"
assertHasSharedContext()
断言日志管理器目前具有给定的共享上下文。您可以将预期的上下文作为数组提供,或者您可以提供真值测试闭包以检查当前上下文。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例测试
/* * implementation... */ Log::shareContext([ 'invocation-id' => '54', ]); /* * assertions... */ Log::assertHasSharedContext([ 'invocation-id' => '54', ]); // ✅ Log::assertCurrentContext( fn (array $context) => $context['invocation-id'] === '54') ); // ✅ Log::assertCurrentContext([ 'invocation-id' => '99', ]); // ❌ wrong invocation ID Log::assertCurrentContext( fn (array $context) => $context['invocation-id'] === '99') ); // ❌ wrong invocation ID
检查
有时在调试测试时,查看已记录的消息很有用。有几个助手可以帮助完成此操作。
dump()
导出通道中的所有日志。您还可以传递基于真值的闭包以过滤要导出的日志。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
/* * implementation... */ Log::info('User logged in.'); Log::channel('slack')->alert('Stripe request initiated.'); /* * inspection... */ Log::dump(); // array:1 [ // 0 => array:4 [ // "level" => "info" // "message" => "User logged in." // "context" => [] // "channel" => "stack" // ] // ] Log::channel('slack')->dump(); // array:1 [ // 0 => array:4 [ // "level" => "alert" // "message" => "Stripe request initiated." // "context" => [] // "channel" => "slack" // ] // ]
dd()
与dump
相同,但还会结束执行。
dumpAll()
导出所有通道的日志。也接受真值测试闭包以过滤任何日志。
可以在以下位置调用
- 门面基础
(默认通道) - 通道
- 堆栈
示例用法
/* * implementation... */ Log::info('User logged in.'); Log::channel('slack')->alert('Stripe request initiated.'); /* * inspection... */ Log::dumpAll(); // array:2 [ // 0 => array:4 [ // "level" => "info" // "message" => "User logged in." // "context" => [] // "times_channel_has_been_forgotten_at_time_of_writing_log" => 0 // "channel" => "stack" // ] // 1 => array:4 [ // "level" => "alert" // "message" => "Stripe request initiated." // "context" => [] // "times_channel_has_been_forgotten_at_time_of_writing_log" => 0 // "channel" => "slack" // ] // ]
ddAll()
与dumpAll()
相同,但也会结束执行。
其他 API
logs()
从通道或堆栈获取所有日志条目的集合。
可以在以下位置调用
- 门面基础(默认通道)
- 通道
- 堆栈
示例用法
/* * implementation... */ Log::channel('slack')->info('User logged in.'); Log::channel('slack')->alert('Stripe request initiated.'); /* * example usage... */ $logs = Log::channel('slack')->logs(); assert($logs->count() === 2); ✅
allLogs()
与logs()
类似,但它在Facade基类上被调用,并返回来自所有通道和堆栈的日志集合。
可以在以下位置调用
- 门面基础
(默认通道) - 通道
- 堆栈
示例用法
/* * implementation... */ Log::info('User logged in.'); Log::channel('slack')->alert('Stripe request initiated.'); /* * example usage... */ $logs = Log::allLogs(); assert($logs->count() === 2); ✅
致谢
并特别感谢Caneco为标志✨所做的贡献
感谢
您可以自由使用此包,但我要求您联系某人(不是我自己),这个人曾经或目前正在维护或为您的项目中的开源库做出贡献,并对他们的工作表示感谢。考虑您的整个技术栈:包、框架、语言、数据库、操作系统、前端、后端等。