Skip to content

Commit 901ad67

Browse files
committed
assertThrown
1 parent dee10ca commit 901ad67

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php

+26
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,30 @@ protected function assertDoesntThrow(Closure $test)
240240

241241
return $this;
242242
}
243+
244+
/**
245+
* Assert that in instance of $exceptionClass was thrown and return the exception.
246+
*
247+
* @template TThrowable of Throwable
248+
*
249+
* @param \Closure $test
250+
* @param class-string<TThrowable> $exceptionClass
251+
* @param string $noExceptionThrownMessage
252+
* @return TThrowable
253+
*/
254+
protected static function assertThrown(
255+
Closure $test,
256+
string $exceptionClass = Throwable::class,
257+
string $noExceptionThrownMessage = 'Did not throw expected exception',
258+
) {
259+
try {
260+
$test();
261+
} catch (Throwable $exception) {
262+
self::assertInstanceOf($exceptionClass, $exception, "Expected to throw $exceptionClass but threw ".$exception::class);
263+
264+
return $exception;
265+
}
266+
267+
Assert::fail($noExceptionThrownMessage);
268+
}
243269
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Testing\Concerns;
4+
5+
use Illuminate\Foundation\Testing\Concerns\InteractsWithExceptionHandling;
6+
use InvalidArgumentException;
7+
use PHPUnit\Framework\AssertionFailedError;
8+
use PHPUnit\Framework\TestCase;
9+
use RuntimeException;
10+
11+
class InteractsWithExceptionHandlingTest extends TestCase
12+
{
13+
use InteractsWithExceptionHandling;
14+
15+
public function test_assert_thrown_returns_exception_when_throwable()
16+
{
17+
$func = static fn (): never => throw new RuntimeException('My runtime exception');
18+
19+
$thrownException = $this->assertThrown($func);
20+
21+
$this->assertSame('My runtime exception', $thrownException->getMessage());
22+
}
23+
24+
public function test_assert_thrown_returns_exception_when_custom_exception()
25+
{
26+
$func = static function (): never {
27+
throw (new CustomExceptionForInteractsWithExceptionHandlingTest('A message'))->setValue(1993);
28+
};
29+
30+
$thrownException1 = $this->assertThrown($func, RuntimeException::class);
31+
$thrownException2 = $this->assertThrown($func, CustomExceptionForInteractsWithExceptionHandlingTest::class);
32+
33+
foreach ([$thrownException1, $thrownException2] as $exception) {
34+
$this->assertSame('A message', $exception->getMessage());
35+
$this->assertSame(1993, $exception->value);
36+
$this->assertInstanceOf(CustomExceptionForInteractsWithExceptionHandlingTest::class, $exception);
37+
}
38+
}
39+
40+
public function test_assert_thrown_fails_if_not_thrown()
41+
{
42+
$func = static fn (): int => 200;
43+
44+
try {
45+
$this->assertThrown($func);
46+
$this->fail('assertThrown did not raise an assertion error');
47+
} catch (AssertionFailedError $assertionFailedError) {
48+
$this->assertSame('Did not throw expected exception', $assertionFailedError->getMessage());
49+
}
50+
}
51+
52+
public function test_assert_thrown_fails_if_not_subclass()
53+
{
54+
$func = static fn (): never => throw new CustomExceptionForInteractsWithExceptionHandlingTest('invalid argument exception');
55+
56+
try {
57+
$this->assertThrown($func, InvalidArgumentException::class, 'abcd');
58+
$this->fail('assertThrown did not raise an assertion error');
59+
} catch (AssertionFailedError $assertionFailedError) {
60+
$this->assertStringContainsString(
61+
'Expected to throw InvalidArgumentException but threw Illuminate\Tests\Testing\Concerns\CustomExceptionForInteractsWithExceptionHandlingTest',
62+
$assertionFailedError->getMessage()
63+
);
64+
}
65+
}
66+
67+
public function test_assert_thrown_matches_expected_exception_test_passes()
68+
{
69+
$func = static fn (): never => throw new CustomExceptionForInteractsWithExceptionHandlingTest('zzz');
70+
71+
$this->assertThrown($func, CustomExceptionForInteractsWithExceptionHandlingTest::class);
72+
$this->assertThrown($func, RuntimeException::class);
73+
}
74+
}
75+
76+
class CustomExceptionForInteractsWithExceptionHandlingTest extends RuntimeException
77+
{
78+
public $value;
79+
80+
public function setValue($value): self
81+
{
82+
$this->value = $value;
83+
84+
return $this;
85+
}
86+
}

0 commit comments

Comments
 (0)