Hướng dẫn dùng assert exception trong PHP
TLDR; scroll to: Use PHPUnit's Data Provider Show Nội dung chính
Nội dung chính
Nội dung chính
Nội dung chính
Nội dung chính
PHPUnit 9.5 offers following methods to test exceptions:
However the Documentation is vague about the order of any of the above methods in the test code. If you get used to using assertions for example:
output:
you may be surprised by failing the exception test:
output:
The error is because:
Unlike errors, exceptions don't have a capability to recover from them and make PHP continue code execution as if there was no exception at all. Therefore PHPUnit does not even reach the place:
if it was preceded by:
Moreover, PHPUnit will never be able to reach that place, no matter its exception catching capabilities. Therefore using any of the PHPUnit's exception testing methods:
must be before a code where an exception is expected to be thrown in contrary to an assertion that is placed after an actual value is set. A proper order of using exception test:
Because call to PHPUnit internal methods for testing exceptions must be before an exception is thrown it makes sense that PHPUnit methods related to test exceptions start from Knowing already that:
You should be able to easily spot a bug in this test:
The first The second that should fail expects The test's output is:
No it is far from Note that the output has:
where the count of tests is right but there is only There should be 2 assertions = That's simply because PHPUnit is done with executing
that is a one way ticket outside the scope of the
will never be executed and that's why from PHPUnit point of view the test result is That's not a good news if you would like to use multiple
gives wrong:
because once an exception is thrown all other How to test multiple Exceptions?Split multiple exceptions into separate tests:
gives:
This method however has a downside at its fundamental approach - for every exception thrown you need a separate test. That will make a flood of tests just to check exceptions. Catch an exception and check it with an assertionIf you can't continue script execution after an exception was thrown you may simply catch an expected exception and later get all data about it with the methods an exception provides and use that with combination of expected values and assertions:
gives:
Use PHPUnit's Data ProviderPHPUnit has a helpful mechanism called a Data Provider. A data provider is a method that returns the data (array) with data
sets. A single data set is used as the argument(s) when a test method - If the data provider returns more than one data set then the test method will be run multiple times, each time with another data set. That is helpful when testing multiple exceptions or/and multiple exception's properties like class name, message, code because even though:
PHPUnit will run the test method multiple times, each time with different data set so instead of testing for example multiple exceptions in a single test method run (that will fail). That's why we may make a test method responsible for testing just one exception at the time but run that test method multiple times with different input data and expected exception by using the PHPUnit's data provider. Definition
of the data provider method can be done by doing
gives result:
Note that even there is just a one test method in the entire
So even the line:
threw the exception at the first time that was no problem for testing another exception with the same test method because PHPUnit ran it again with different data set thanks to the data provider. Each data set returned by the data provider can be named, you just need to use a string as a key under which a data set is stored. Therefore the expected exception class name is used twice. As a key of data set array and as a value (under 'className' key) that is later used as an argument for Using strings as key names for data sets makes that pretty and self explanatory summary:
and if you change the line:
to:
of the to get wrong exceptions thrown and run the PHPUnit again you'll see:
as expected:
with exactly pointed out the data sets' names that caused some problems:
Making
and running PHPUnit again gives:
It looks that using a data provider has several advantages:
Testing Exceptions Gotchasexception of type "TypeError"With PHP7 datatype support this test:
fails with the output:
even though there is in the method
and the test passes an array instead of a string:
PHP does not reach the code:
because
the exception is thrown earlier due to the type typing
therefore the exception of type "TypeError" againKnowing that we don't need
Modifying also In both tests we expect instead of a specific exception class like
the test result is:
passes with but
It looks confusing that PHPUnit complained that exception The problem is that PHPUnit misleads you with the description as above because
whereas
and thus That's why throwing the However both Therefore changing in both tests
to
makes test green:
See the list of Errors and Exception classes and how they are related to each other. Just to be clear: it is a good practice to use a specific exception or error for unit test instead of a
generic |