-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prefer assertException over expectException #3071
Comments
I wrote everything I have to say on the subject in https://thephp.cc/news/2016/02/questioning-phpunit-best-practices. IMO, |
Thanks for the link. |
As you mention in your post, the suggestion has been brought up, dismissed, and implemented as a plugin by others. Quoting your link:
Here are a few additional arguments surrounding the case:
|
Pardon me if I take this up again. I especially support the point #4. When the same aspect is tested, it should be possible to test it in the same test method. Splitting helps specificity and readability but that should be an optional benefit, not a requirement. I see and acknowledge the reasoning behind it about enforcing best practices, but I see the current limit 1exceptedException-1method being driven mostly by technical implementation (yet, I dunno how much work & hassle is needed to implement an Also I think also point #2 has its reason to be. The expected syntax has arbitrary changed |
@Pictor13 If you're interested I implemented I'd be happy to submit a PR if @sebastianbergmann would like. Also @keradus interested to hear what you have to add. |
So, I have some code that I was hoping on having a callback that can test FooException ->getBar() matches my expectation, like I can do for assertions. Seems silly to have to use a plugin for something that is so core to PHP. Since PHPUnit does not support this right now, and I can't easily use a plugin (enterprise software etc), I guess I will have to not use expectException, and wrap the method under test with try/catch in my actual test class, catch the exception and run my assertions. |
I can't use
will leave me with foo entry, even though test succeeds and I think that
One needs to remember as well that |
Why would Also, your alternative is correct: |
@sebastianbergmann This link is dead. |
@sebastianbergmann Maybe it wasn't made clear from previous comments, I would like to challenge the approach: I think most of us don't want to test multiple exceptions in a test case, but check attributes of the exceptions, or events that should happen in case of the exception. Example: I expect an API log on error: $exception = null;
try {
$now = new DateTimeImmutable('now');
$this->authenticate(clientSecret: 'invalid');
} catch (Throwable $e) {
$exception = $e;
}
$this->assertInstanceOf(ClientException::class, $exception);
$this->assertLogEntry($now, false, 'Client authentication failed'); If you think this code is against best practices, can you suggest how to test such a condition in a "good" way? |
For integration testing of APIs I came to the exact same conclusion. There's often other things to assert after an exception, next to the exception, and for API stuff integration tests are really important. So much can happen in different cases, pure unit won't cut it. TL;DR: for this case I've been using something like this to great success for years: public static function assertExceptionCaptured(
callable $fn,
string $expectedExceptionClass,
string $expectedExceptionMessage = null
): Throwable {
$exception = null;
try {
$fn();
} catch (Throwable $exception) {
// Deliberately empty
}
if (null === $exception) {
throw new ExpectationFailedException(
"Expected to catch exception of type $expectedExceptionClass but none was caught"
);
}
$exceptionClass = $exception::class;
$msg = "Expected to catch $expectedExceptionClass but caught "
. $exception::class . ' instead: '
. $exception->getMessage()
. "\n"
. $exception->getTraceAsString()
. "\n";
self::assertSame($expectedExceptionClass, $exceptionClass, $msg);
if (null !== $expectedExceptionMessage) {
self::assertSame($expectedExceptionMessage, $exception->getMessage());
}
return $exception;
} |
Goal: to test exceptions.
After reading through SO I found #1798, which was closed in a routine issue clean-up. As suggested, I am re-opening this issue.
Please forgive any ignorance I have about the design decisions of the
expectException
family of methods, but I still find this particular suggestion to be a good direction on having a callback-based exception testing pattern.While I realize this example is far from a complete replacement, I think we could build from this pattern to give users more control over exception testing, and a more familiar assertion pattern that doesn't require calling
$this->fail()
, etc.Here is a theoretical usage example (of a currently non-existent
assertException
):The text was updated successfully, but these errors were encountered: