Skip to content

Commit 0c68ae1

Browse files
authored
[10.x] Allow deprecation logging in tests (#49457)
* Allow more config to be controllable * Introduce configurable value * Use env, not config * make mocks strict
1 parent 1a84e34 commit 0c68ae1

File tree

2 files changed

+113
-50
lines changed

2 files changed

+113
-50
lines changed

src/Illuminate/Foundation/Bootstrap/HandleExceptions.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Contracts\Debug\ExceptionHandler;
88
use Illuminate\Contracts\Foundation\Application;
99
use Illuminate\Log\LogManager;
10+
use Illuminate\Support\Env;
1011
use Monolog\Handler\NullHandler;
1112
use Symfony\Component\Console\Output\ConsoleOutput;
1213
use Symfony\Component\ErrorHandler\Error\FatalError;
@@ -118,7 +119,7 @@ protected function shouldIgnoreDeprecationErrors()
118119
{
119120
return ! class_exists(LogManager::class)
120121
|| ! static::$app->hasBeenBootstrapped()
121-
|| static::$app->runningUnitTests();
122+
|| (static::$app->runningUnitTests() && ! Env::get('LOG_DEPRECATIONS_WHILE_TESTING'));
122123
}
123124

124125
/**

tests/Foundation/Bootstrap/HandleExceptionsTest.php

Lines changed: 111 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77
use Illuminate\Foundation\Application;
88
use Illuminate\Foundation\Bootstrap\HandleExceptions;
99
use Illuminate\Log\LogManager;
10+
use Illuminate\Support\Env;
1011
use Mockery as m;
1112
use Monolog\Handler\NullHandler;
1213
use PHPUnit\Framework\TestCase;
1314
use ReflectionClass;
15+
use RuntimeException;
1416

1517
class HandleExceptionsTest extends TestCase
1618
{
1719
protected $app;
1820
protected $config;
19-
protected $handleExceptions;
2021

2122
protected function setUp(): void
2223
{
@@ -27,40 +28,38 @@ protected function setUp(): void
2728
$this->app->singleton('config', function () {
2829
return $this->config;
2930
});
31+
}
3032

31-
$this->handleExceptions = new HandleExceptions();
32-
33-
with(new ReflectionClass($this->handleExceptions), function ($reflection) {
34-
$property = $reflection->getProperty('app');
35-
36-
$property->setValue(
37-
$this->handleExceptions,
38-
tap($this->app, function ($app) {
39-
$app->shouldReceive('runningUnitTests')->andReturn(false);
40-
$app->shouldReceive('hasBeenBootstrapped')->andReturn(true);
41-
})
42-
);
33+
protected function handleExceptions()
34+
{
35+
return tap(new HandleExceptions(), function ($instance) {
36+
with(new ReflectionClass($instance), function ($reflection) use ($instance) {
37+
$reflection->getProperty('app')->setValue($instance, $this->app);
38+
});
4339
});
4440
}
4541

4642
protected function tearDown(): void
4743
{
4844
Application::setInstance(null);
45+
m::close();
4946
}
5047

5148
public function testPhpDeprecations()
5249
{
5350
$logger = m::mock(LogManager::class);
5451
$this->app->instance(LogManager::class, $logger);
52+
$this->app->expects('runningUnitTests')->andReturn(false);
53+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
5554

56-
$logger->shouldReceive('channel')->with('deprecations')->andReturnSelf();
57-
$logger->shouldReceive('warning')->with(sprintf('%s in %s on line %s',
55+
$logger->expects('channel')->with('deprecations')->andReturnSelf();
56+
$logger->expects('warning')->with(sprintf('%s in %s on line %s',
5857
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
5958
'/home/user/laravel/routes/web.php',
6059
17
6160
));
6261

63-
$this->handleExceptions->handleError(
62+
$this->handleExceptions()->handleError(
6463
E_DEPRECATED,
6564
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
6665
'/home/user/laravel/routes/web.php',
@@ -72,14 +71,16 @@ public function testPhpDeprecationsWithStackTraces()
7271
{
7372
$logger = m::mock(LogManager::class);
7473
$this->app->instance(LogManager::class, $logger);
74+
$this->app->expects('runningUnitTests')->andReturn(false);
75+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
7576

7677
$this->config->set('logging.deprecations', [
7778
'channel' => 'null',
7879
'trace' => true,
7980
]);
8081

81-
$logger->shouldReceive('channel')->with('deprecations')->andReturnSelf();
82-
$logger->shouldReceive('warning')->with(
82+
$logger->expects('channel')->with('deprecations')->andReturnSelf();
83+
$logger->expects('warning')->with(
8384
m::on(fn (string $message) => (bool) preg_match(
8485
<<<REGEXP
8586
#ErrorException: str_contains\(\): Passing null to parameter \#2 \(\\\$needle\) of type string is deprecated in /home/user/laravel/routes/web\.php:17
@@ -94,7 +95,7 @@ public function testPhpDeprecationsWithStackTraces()
9495
))
9596
);
9697

97-
$this->handleExceptions->handleError(
98+
$this->handleExceptions()->handleError(
9899
E_DEPRECATED,
99100
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
100101
'/home/user/laravel/routes/web.php',
@@ -106,20 +107,22 @@ public function testNullValueAsChannelUsesNullDriver()
106107
{
107108
$logger = m::mock(LogManager::class);
108109
$this->app->instance(LogManager::class, $logger);
110+
$this->app->expects('runningUnitTests')->andReturn(false);
111+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
109112

110113
$this->config->set('logging.deprecations', [
111114
'channel' => null,
112115
'trace' => false,
113116
]);
114117

115-
$logger->shouldReceive('channel')->with('deprecations')->andReturnSelf();
116-
$logger->shouldReceive('warning')->with(sprintf('%s in %s on line %s',
118+
$logger->expects('channel')->with('deprecations')->andReturnSelf();
119+
$logger->expects('warning')->with(sprintf('%s in %s on line %s',
117120
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
118121
'/home/user/laravel/routes/web.php',
119122
17
120123
));
121124

122-
$this->handleExceptions->handleError(
125+
$this->handleExceptions()->handleError(
123126
E_DEPRECATED,
124127
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
125128
'/home/user/laravel/routes/web.php',
@@ -136,15 +139,17 @@ public function testUserDeprecations()
136139
{
137140
$logger = m::mock(LogManager::class);
138141
$this->app->instance(LogManager::class, $logger);
142+
$this->app->expects('runningUnitTests')->andReturn(false);
143+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
139144

140-
$logger->shouldReceive('channel')->with('deprecations')->andReturnSelf();
141-
$logger->shouldReceive('warning')->with(sprintf('%s in %s on line %s',
145+
$logger->expects('channel')->with('deprecations')->andReturnSelf();
146+
$logger->expects('warning')->with(sprintf('%s in %s on line %s',
142147
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
143148
'/home/user/laravel/routes/web.php',
144149
17
145150
));
146151

147-
$this->handleExceptions->handleError(
152+
$this->handleExceptions()->handleError(
148153
E_USER_DEPRECATED,
149154
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
150155
'/home/user/laravel/routes/web.php',
@@ -156,14 +161,16 @@ public function testUserDeprecationsWithStackTraces()
156161
{
157162
$logger = m::mock(LogManager::class);
158163
$this->app->instance(LogManager::class, $logger);
164+
$this->app->expects('runningUnitTests')->andReturn(false);
165+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
159166

160167
$this->config->set('logging.deprecations', [
161168
'channel' => 'null',
162169
'trace' => true,
163170
]);
164171

165-
$logger->shouldReceive('channel')->with('deprecations')->andReturnSelf();
166-
$logger->shouldReceive('warning')->with(
172+
$logger->expects('channel')->with('deprecations')->andReturnSelf();
173+
$logger->expects('warning')->with(
167174
m::on(fn (string $message) => (bool) preg_match(
168175
<<<REGEXP
169176
#ErrorException: str_contains\(\): Passing null to parameter \#2 \(\\\$needle\) of type string is deprecated in /home/user/laravel/routes/web\.php:17
@@ -178,7 +185,7 @@ public function testUserDeprecationsWithStackTraces()
178185
))
179186
);
180187

181-
$this->handleExceptions->handleError(
188+
$this->handleExceptions()->handleError(
182189
E_USER_DEPRECATED,
183190
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
184191
'/home/user/laravel/routes/web.php',
@@ -197,7 +204,7 @@ public function testErrors()
197204
$this->expectException(ErrorException::class);
198205
$this->expectExceptionMessage('Something went wrong');
199206

200-
$this->handleExceptions->handleError(
207+
$this->handleExceptions()->handleError(
201208
E_ERROR,
202209
'Something went wrong',
203210
'/home/user/laravel/src/Providers/AppServiceProvider.php',
@@ -209,9 +216,11 @@ public function testEnsuresDeprecationsDriver()
209216
{
210217
$logger = m::mock(LogManager::class);
211218
$this->app->instance(LogManager::class, $logger);
219+
$this->app->expects('runningUnitTests')->andReturn(false);
220+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
212221

213-
$logger->shouldReceive('channel')->andReturnSelf();
214-
$logger->shouldReceive('warning');
222+
$logger->expects('channel')->andReturnSelf();
223+
$logger->expects('warning');
215224

216225
$this->config->set('logging.channels.stack', [
217226
'driver' => 'stack',
@@ -220,7 +229,7 @@ public function testEnsuresDeprecationsDriver()
220229
]);
221230
$this->config->set('logging.deprecations', 'stack');
222231

223-
$this->handleExceptions->handleError(
232+
$this->handleExceptions()->handleError(
224233
E_USER_DEPRECATED,
225234
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
226235
'/home/user/laravel/routes/web.php',
@@ -241,11 +250,13 @@ public function testEnsuresNullDeprecationsDriver()
241250
{
242251
$logger = m::mock(LogManager::class);
243252
$this->app->instance(LogManager::class, $logger);
253+
$this->app->expects('runningUnitTests')->andReturn(false);
254+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
244255

245-
$logger->shouldReceive('channel')->andReturnSelf();
246-
$logger->shouldReceive('warning');
256+
$logger->expects('channel')->andReturnSelf();
257+
$logger->expects('warning');
247258

248-
$this->handleExceptions->handleError(
259+
$this->handleExceptions()->handleError(
249260
E_USER_DEPRECATED,
250261
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
251262
'/home/user/laravel/routes/web.php',
@@ -262,11 +273,13 @@ public function testEnsuresNullLogDriver()
262273
{
263274
$logger = m::mock(LogManager::class);
264275
$this->app->instance(LogManager::class, $logger);
276+
$this->app->expects('runningUnitTests')->andReturn(false);
277+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
265278

266-
$logger->shouldReceive('channel')->andReturnSelf();
267-
$logger->shouldReceive('warning');
279+
$logger->expects('channel')->andReturnSelf();
280+
$logger->expects('warning');
268281

269-
$this->handleExceptions->handleError(
282+
$this->handleExceptions()->handleError(
270283
E_USER_DEPRECATED,
271284
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
272285
'/home/user/laravel/routes/web.php',
@@ -283,16 +296,18 @@ public function testDoNotOverrideExistingNullLogDriver()
283296
{
284297
$logger = m::mock(LogManager::class);
285298
$this->app->instance(LogManager::class, $logger);
299+
$this->app->expects('runningUnitTests')->andReturn(false);
300+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
286301

287-
$logger->shouldReceive('channel')->andReturnSelf();
288-
$logger->shouldReceive('warning');
302+
$logger->expects('channel')->andReturnSelf();
303+
$logger->expects('warning');
289304

290305
$this->config->set('logging.channels.null', [
291306
'driver' => 'monolog',
292307
'handler' => CustomNullHandler::class,
293308
]);
294309

295-
$this->handleExceptions->handleError(
310+
$this->handleExceptions()->handleError(
296311
E_USER_DEPRECATED,
297312
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
298313
'/home/user/laravel/routes/web.php',
@@ -313,7 +328,50 @@ public function testNoDeprecationsDriverIfNoDeprecationsHereSend()
313328

314329
public function testIgnoreDeprecationIfLoggerUnresolvable()
315330
{
316-
$this->handleExceptions->handleError(
331+
$this->app->expects('runningUnitTests')->andReturn(false);
332+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
333+
334+
$this->handleExceptions()->handleError(
335+
E_DEPRECATED,
336+
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
337+
'/home/user/laravel/routes/web.php',
338+
17
339+
);
340+
}
341+
342+
public function testItIgnoreDeprecationLoggingWhenRunningUnitTests()
343+
{
344+
$resolved = false;
345+
$this->app->bind(LogManager::class, function () use (&$resolved) {
346+
$resolved = true;
347+
348+
throw new RuntimeException();
349+
});
350+
$this->app->expects('runningUnitTests')->andReturn(true);
351+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
352+
353+
$this->handleExceptions()->handleError(
354+
E_DEPRECATED,
355+
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
356+
'/home/user/laravel/routes/web.php',
357+
17
358+
);
359+
360+
$this->assertFalse($resolved);
361+
}
362+
363+
public function testItCanForceViaConfigDeprecationLoggingWhenRunningUnitTests()
364+
{
365+
$logger = m::mock(LogManager::class);
366+
$logger->expects('channel')->andReturnSelf();
367+
$logger->expects('warning');
368+
$this->app->instance(LogManager::class, $logger);
369+
$this->app->expects('runningUnitTests')->andReturn(true);
370+
$this->app->expects('hasBeenBootstrapped')->andReturn(true);
371+
372+
Env::getRepository()->set('LOG_DEPRECATIONS_WHILE_TESTING', true);
373+
374+
$this->handleExceptions()->handleError(
317375
E_DEPRECATED,
318376
'str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated',
319377
'/home/user/laravel/routes/web.php',
@@ -323,31 +381,35 @@ public function testIgnoreDeprecationIfLoggerUnresolvable()
323381

324382
public function testForgetApp()
325383
{
326-
$appResolver = fn () => with(new ReflectionClass($this->handleExceptions), function ($reflection) {
384+
$instance = $this->handleExceptions();
385+
386+
$appResolver = fn () => with(new ReflectionClass($instance), function ($reflection) use ($instance) {
327387
$property = $reflection->getProperty('app');
328388

329-
return $property->getValue($this->handleExceptions);
389+
return $property->getValue($instance);
330390
});
331391

332392
$this->assertNotNull($appResolver());
333393

334-
handleExceptions::forgetApp();
394+
HandleExceptions::forgetApp();
335395

336396
$this->assertNull($appResolver());
337397
}
338398

339399
public function testHandlerForgetsPreviousApp()
340400
{
341-
$appResolver = fn () => with(new ReflectionClass($this->handleExceptions), function ($reflection) {
401+
$instance = $this->handleExceptions();
402+
403+
$appResolver = fn () => with(new ReflectionClass($instance), function ($reflection) use ($instance) {
342404
$property = $reflection->getProperty('app');
343405

344-
return $property->getValue($this->handleExceptions);
406+
return $property->getValue($instance);
345407
});
346408

347409
$this->assertSame($this->app, $appResolver());
348410

349-
$this->handleExceptions->bootstrap($newApp = tap(m::mock(Application::class), function ($app) {
350-
$app->shouldReceive('environment')->once()->andReturn(true);
411+
$instance->bootstrap($newApp = tap(m::mock(Application::class), function ($app) {
412+
$app->expects('environment')->andReturn(true);
351413
}));
352414

353415
$this->assertNotSame($this->app, $appResolver());

0 commit comments

Comments
 (0)