Skip to content

Commit a4ba261

Browse files
Merge pull request #200 from Yoast/feature/3.x/new-expectuserdeprecation-polyfill-trait
PHPUnit 11 | ExpectUserDeprecationtrait: polyfill the TestCase::expectUserDeprecation*() methods
2 parents d6537e8 + 37f2e99 commit a4ba261

13 files changed

+199
-76
lines changed

.github/workflows/test.yml

+7-73
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ jobs:
4646
# it would result PHP 7.0 - 7.4 all using PHPUnit 6.4.4, which is not the intention.
4747
# It also would run into trouble with PHP 8.5.12 being used on PHP 8.0+, while the
4848
# 8.5.12 release still contained a bug which makes it incompatible with PHP 8.1+,
49-
# even though it officially allows for it..
49+
# even though it officially allows for it.
50+
#
51+
# Note: PHPUnit 10 is not supported for the PHPUnit Polyfills 3.x branch, so there are
52+
# no builds against PHPUnit 10!
5053
- php: '7.0'
5154
phpunit: '6.4.4'
5255
coverage: true
@@ -86,12 +89,6 @@ jobs:
8689
phpunit: '9.3.0'
8790
coverage: true
8891
experimental: false
89-
- php: '8.1'
90-
# Specifically set at 10.0.12 minimum to prevent needing a toggle in the tests for something
91-
# related to the ArrayIsList polyfill, but not necessarily relevant.
92-
phpunit: '10.0.12'
93-
coverage: true
94-
experimental: false
9592
- php: '8.2'
9693
phpunit: '9.3.0'
9794
coverage: true
@@ -100,10 +97,6 @@ jobs:
10097
phpunit: '~11.1.0' # See note above about PHPUnit 11.2.
10198
coverage: true
10299
experimental: false
103-
- php: '8.3'
104-
phpunit: '10.1.0'
105-
coverage: true
106-
experimental: false
107100
- php: '8.3'
108101
phpunit: '11.0.0'
109102
coverage: true
@@ -114,10 +107,6 @@ jobs:
114107
phpunit: '^9.6'
115108
coverage: false
116109
experimental: true
117-
- php: 'nightly'
118-
phpunit: '^10.5'
119-
coverage: false
120-
experimental: true
121110
- php: 'nightly'
122111
phpunit: 'auto' # PHPUnit 11.x.
123112
coverage: false
@@ -132,9 +121,6 @@ jobs:
132121

133122
continue-on-error: ${{ matrix.experimental }}
134123

135-
env:
136-
EXTRA_PHPUNIT_CLIARGS: '--fail-on-deprecation --fail-on-notice'
137-
138124
steps:
139125
- name: Checkout code
140126
uses: actions/checkout@v4
@@ -178,40 +164,23 @@ jobs:
178164
- name: "DEBUG: Show grabbed version"
179165
run: echo ${{ steps.phpunit_version.outputs.VERSION }}
180166

181-
# NEEDS_MIGRATION toggle has two functions:
182-
# 1. yes/no run PHPUnit "migrate-configuration" for PHPUnit 10.1+.
183-
# 2. yes/no pass the "EXTRA_PHPUNIT_CLIARGS" on PHPUnit 10.1+ (which can't be added to the config as that would
184-
# make the config incompatible with PHPUnit 10.0).
185-
# The variable should only be set for the "yes" cases.
186167
- name: Determine PHPUnit config
187168
id: phpunit_config
188169
run: |
189170
if [ "${{ matrix.phpunit == 'dev-main' }}" == "true" ]; then
190171
echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT
191-
echo 'NEEDS_MIGRATION=true' >> $GITHUB_OUTPUT
192-
elif [ "${{ steps.phpunit_version.outputs.VERSION }}" == "10.0" ]; then
193-
echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT
194-
elif [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) || startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then
172+
elif [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then
195173
echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT
196-
echo 'NEEDS_MIGRATION=true' >> $GITHUB_OUTPUT
197174
else
198175
echo 'FILE=phpunit.xml.dist' >> $GITHUB_OUTPUT
199176
fi
200177
201-
# Migrate PHPUnit configuration to deal with changes in the coverage/source setting across PHPUnit 10.x
202-
# versions as otherwise the warnings about these would fail the build (which to me, feels like a bug).
203-
- name: "Migrate configuration (PHPUnit 10.1+)"
204-
if: ${{ steps.phpunit_config.outputs.NEEDS_MIGRATION }}
205-
continue-on-error: true
206-
run: vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }} --migrate-configuration
207-
208178
- name: "Run the unit tests"
209179
# Don't fail the build on a test run failure against a future PHPUnit version.
210180
continue-on-error: ${{ matrix.phpunit == 'dev-main' }}
211181
run: >
212182
vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }}
213183
${{ ! matrix.coverage && '--no-coverage' || '' }}
214-
${{ steps.phpunit_config.outputs.NEEDS_MIGRATION && env.EXTRA_PHPUNIT_CLIARGS || '' }}
215184
216185
- name: Upload coverage results to Coveralls
217186
if: ${{ success() && matrix.coverage == true }}
@@ -310,21 +279,7 @@ jobs:
310279
phpunit: '9'
311280
coverage: true
312281

313-
# PHPUnit 10 is fully supported for the officially supported PHP versions.
314-
- php: '8.1'
315-
phpunit: '10.0'
316-
coverage: true
317-
- php: '8.1'
318-
phpunit: '10'
319-
- php: '8.2'
320-
phpunit: '10.0'
321-
- php: '8.2'
322-
phpunit: '10'
323-
- php: '8.3'
324-
phpunit: '10.0'
325-
- php: '8.3'
326-
phpunit: '10'
327-
coverage: true
282+
# PHPUnit 10 is NOT supported in PHPUnit Polyfills 3.x.
328283

329284
# PHPUnit 11 is fully supported for the officially supported PHP versions.
330285
#
@@ -344,18 +299,13 @@ jobs:
344299
# Experimental builds.
345300
- php: 'nightly'
346301
phpunit: '9'
347-
- php: 'nightly'
348-
phpunit: '10'
349302
- php: 'nightly'
350303
phpunit: '11'
351304

352305
name: "PHAR test: PHP ${{ matrix.php }} - PHPUnit: ${{matrix.phpunit}}"
353306

354307
continue-on-error: ${{ matrix.php == 'nightly' }}
355308

356-
env:
357-
EXTRA_PHPUNIT_CLIARGS: '--fail-on-deprecation --fail-on-notice'
358-
359309
steps:
360310
- name: Checkout code
361311
uses: actions/checkout@v4
@@ -403,35 +353,19 @@ jobs:
403353
- name: "DEBUG: Show grabbed version"
404354
run: echo ${{ steps.phpunit_version.outputs.VERSION }}
405355

406-
# NEEDS_MIGRATION toggle has two functions:
407-
# 1. yes/no run PHPUnit "migrate-configuration" for PHPUnit 10.1+.
408-
# 2. yes/no pass the "EXTRA_PHPUNIT_CLIARGS" on PHPUnit 10.1+ (which can't be added to the config as that would
409-
# make the config incompatible with PHPUnit 10.0).
410-
# The variable should only be set for the "yes" cases.
411356
- name: Determine PHPUnit config
412357
id: phpunit_config
413358
run: |
414-
if [ "${{ steps.phpunit_version.outputs.VERSION }}" == "10.0" ]; then
415-
echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT
416-
elif [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) || startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then
359+
if [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then
417360
echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT
418-
echo 'NEEDS_MIGRATION=true' >> $GITHUB_OUTPUT
419361
else
420362
echo 'FILE=phpunit.xml.dist' >> $GITHUB_OUTPUT
421363
fi
422364
423-
# Migrate PHPUnit configuration to deal with changes in the coverage/source setting across PHPUnit 10.x
424-
# versions as otherwise the warnings about these would fail the build (which to me, feels like a bug).
425-
- name: "Migrate configuration (PHPUnit 10.1+)"
426-
if: ${{ steps.phpunit_config.outputs.NEEDS_MIGRATION }}
427-
continue-on-error: true
428-
run: phpunit -c ${{ steps.phpunit_config.outputs.FILE }} --migrate-configuration
429-
430365
- name: "Run the unit tests"
431366
run: >
432367
phpunit -c ${{ steps.phpunit_config.outputs.FILE }}
433368
${{ ! matrix.coverage && '--no-coverage' || '' }}
434-
${{ steps.phpunit_config.outputs.NEEDS_MIGRATION && env.EXTRA_PHPUNIT_CLIARGS || '' }}
435369
436370
- name: Upload coverage results to Coveralls
437371
if: ${{ success() && matrix.coverage }}

README.md

+30
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,36 @@ Refactoring tests which still use `Assert::assertArraySubset()` to use the new a
443443
[`Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys()`]: https://docs.phpunit.de/en/main/assertions.html#assertarrayisidenticaltoarrayonlyconsideringlistofkeys
444444
[`Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys()`]: https://docs.phpunit.de/en/main/assertions.html#assertarrayisidenticaltoarrayignoringlistofkeys
445445

446+
#### PHPUnit < 11.0.0: `Yoast\PHPUnitPolyfills\Polyfills\ExpectUserDeprecation`
447+
448+
| | |
449+
| -------------------------------------------- | --------------------------------------------------- |
450+
| [`TestCase::expectUserDeprecationMessage()`] | [`TestCase::expectUserDeprecationMessageMatches()`] |
451+
452+
These methods were introduced in PHPUnit 11.0.0.
453+
454+
This functionality resembles the functionality previously offered by the `TestCase::expectDeprecationMessage()` and `TestCase::expectDeprecationMessageMatches()` methods, which were removed in PHPUnit 10.0.0.
455+
456+
The polyfill use the old methods under the hood for PHPUnit <= 9, however, there are some pertinent differences in behaviour between the old and the new methods, which users of the polyfill should be aware of.
457+
458+
| PHPUnit <= 9.x | PHPUnit >= 11.0 |
459+
| -------------- | --------------- |
460+
| Only one deprecation can be expected per test | Multiple deprecations can be expected per test |
461+
| The test stops running as soon as the deprecation message has been seen | The test will be executed completely, independently of the deprecation notice |
462+
| The message passed to `expectUserDeprecationMessage()` will be compared as a substring | The message passed to `expectUserDeprecationMessage()` must be an exact match |
463+
| Can expect both PHP native and user-land deprecation notices | Can only expect user-land deprecation notices, i.e. `E_USER_DEPRECATED`, not `E_DEPRECATED` |
464+
465+
Please keep these differences in mind when writing tests using the `expectUserDeprecationMessage*()` methods.
466+
467+
Note: on PHPUnit 9.5.x, when using the `expectUserDeprecationMessage*()` expectations, a "_Expecting E_DEPRECATED and E_USER_DEPRECATED is deprecated and will no longer be possible in PHPUnit 10._" deprecation will be shown in the test output.
468+
As long at the actual test uses the `expectUserDeprecationMessage*()` expectations, this depreation message can be safely ignored.
469+
470+
> :information_source: Important: when using the `expectUserDeprecationMessage*()` expectation(s) in a test, the test should be annotated with a [`#[IgnoreDeprecations]`][ignoredeprecations-attribute] attribute.
471+
472+
[`TestCase::expectUserDeprecationMessage()`]: https://docs.phpunit.de/en/main/error-handling.html#expecting-deprecations-e-user-deprecated
473+
[`TestCase::expectUserDeprecationMessageMatches()`]: https://docs.phpunit.de/en/main/error-handling.html#expecting-deprecations-e-user-deprecated
474+
[ignoredeprecations-attribute]: https://docs.phpunit.de/en/main/attributes.html#ignoredeprecations
475+
446476
#### PHPUnit < 11.2.0: `Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals`
447477

448478
Polyfills the [`Assert::assertObjectNotEquals()`] method to verify two (value) objects are **_not_** considered equal.

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
"require": {
2929
"php": ">=7.0",
30-
"phpunit/phpunit": "^6.4.4 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0"
30+
"phpunit/phpunit": "^6.4.4 || ^7.0 || ^8.0 || ^9.0 || ^11.0"
3131
},
3232
"require-dev": {
3333
"php-parallel-lint/php-console-highlighter": "^1.0.0",

phpstan.neon.dist

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ parameters:
2626
count: 2
2727
path: src/Polyfills/AssertIsList.php
2828

29+
-
30+
message: '`^Call to an undefined method Yoast\\PHPUnitPolyfills\\TestCases\\[X]?TestCase::expectExceptionMessageRegExp\(\)\.$`'
31+
count: 2
32+
path: src/Polyfills/ExpectUserDeprecation.php
33+
2934
# Level 5
3035
-
3136
# False positive, a string callback is perfectly fine, especially for static methods.

phpunit10.xml.dist

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phpunit
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
4+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.0/phpunit.xsd"
55
backupGlobals="true"
66
bootstrap="./tests/bootstrap.php"
77
beStrictAboutOutputDuringTests="true"
@@ -14,6 +14,8 @@
1414
displayDetailsOnTestsThatTriggerNotices="true"
1515
displayDetailsOnTestsThatTriggerDeprecations="true"
1616
failOnWarning="true"
17+
failOnNotice="true"
18+
failOnDeprecation="true"
1719
>
1820

1921
<testsuites>
@@ -22,13 +24,16 @@
2224
</testsuite>
2325
</testsuites>
2426

25-
<coverage includeUncoveredFiles="true">
27+
<source>
2628
<include>
2729
<directory suffix=".php">./src/</directory>
2830
</include>
2931
<exclude>
3032
<file>src/Polyfills/AssertClosedResource_Empty.php</file>
3133
</exclude>
34+
</source>
35+
36+
<coverage includeUncoveredFiles="true">
3237
<report>
3338
<text outputFile="php://stdout" showOnlySummary="true"/>
3439
<clover outputFile="build/logs/clover.xml"/>

phpunitpolyfills-autoload.php

+21
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public static function load( $className ) {
8686
self::loadAssertArrayWithListKeys();
8787
return true;
8888

89+
case 'Yoast\PHPUnitPolyfills\Polyfills\ExpectUserDeprecation':
90+
self::loadExpectUserDeprecation();
91+
return true;
92+
8993
case 'Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals':
9094
self::loadAssertObjectNotEquals();
9195
return true;
@@ -339,6 +343,23 @@ public static function loadAssertArrayWithListKeys() {
339343
require_once __DIR__ . '/src/Polyfills/AssertArrayWithListKeys_Empty.php';
340344
}
341345

346+
/**
347+
* Load the ExpectUserDeprecation polyfill or an empty trait with the same name
348+
* if a PHPUnit version is used which already contains this functionality.
349+
*
350+
* @return void
351+
*/
352+
public static function loadExpectUserDeprecation() {
353+
if ( \method_exists( TestCase::class, 'expectUserDeprecationMessage' ) === false ) {
354+
// PHPUnit < 11.0.0.
355+
require_once __DIR__ . '/src/Polyfills/ExpectUserDeprecation.php';
356+
return;
357+
}
358+
359+
// PHPUnit >= 11.0.0.
360+
require_once __DIR__ . '/src/Polyfills/ExpectUserDeprecation_Empty.php';
361+
}
362+
342363
/**
343364
* Load the AssertObjectNotEquals polyfill or an empty trait with the same name
344365
* if a PHPUnit version is used which already contains this functionality.
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Yoast\PHPUnitPolyfills\Polyfills;
4+
5+
use PHPUnit\Framework\Error\Deprecated;
6+
use PHPUnit\Framework\TestCase;
7+
8+
/**
9+
* Polyfill the TestCase::expectUserDeprecationMessage() and the TestCase::expectUserDeprecationMessageMatches() methods.
10+
*
11+
* Introduced in PHPUnit 11.0.0.
12+
*
13+
* Note: PHPUnit 10 is not and will not be supported for these polyfills.
14+
*
15+
* @link https://github.com/sebastianbergmann/phpunit/pull/5605
16+
*/
17+
trait ExpectUserDeprecation {
18+
19+
/**
20+
* Set expectation for the message when receiving a user defined deprecation notice.
21+
*
22+
* @param string $expectedUserDeprecationMessage The message to expect.
23+
*
24+
* @return void
25+
*/
26+
final protected function expectUserDeprecationMessage( string $expectedUserDeprecationMessage ) {
27+
if ( \method_exists( TestCase::class, 'expectDeprecationMessage' ) ) {
28+
// PHPUnit 8.4.0 - 9.x.
29+
$this->expectDeprecation();
30+
$this->expectDeprecationMessage( $expectedUserDeprecationMessage );
31+
return;
32+
}
33+
34+
// PHPUnit < 8.4.0.
35+
$this->expectException( Deprecated::class );
36+
$this->expectExceptionMessage( $expectedUserDeprecationMessage );
37+
}
38+
39+
/**
40+
* Set expectation for the message when receiving a user defined deprecation notice (regex based).
41+
*
42+
* @param string $expectedUserDeprecationMessageRegularExpression A regular expression which must match the message.
43+
*
44+
* @return void
45+
*/
46+
final protected function expectUserDeprecationMessageMatches( string $expectedUserDeprecationMessageRegularExpression ) {
47+
if ( \method_exists( TestCase::class, 'expectDeprecationMessageMatches' ) ) {
48+
// PHPUnit 8.4.0 - 9.x.
49+
$this->expectDeprecation();
50+
$this->expectDeprecationMessageMatches( $expectedUserDeprecationMessageRegularExpression );
51+
return;
52+
}
53+
54+
// PHPUnit < 8.4.0.
55+
$this->expectException( Deprecated::class );
56+
$this->expectExceptionMessageRegExp( $expectedUserDeprecationMessageRegularExpression );
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Yoast\PHPUnitPolyfills\Polyfills;
4+
5+
/**
6+
* Empty trait for use with PHPUnit >= 11.0.0 in which this polyfill is not needed.
7+
*/
8+
trait ExpectUserDeprecation {}

src/TestCases/TestCasePHPUnitGte8.php

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectProperty;
1515
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
1616
use Yoast\PHPUnitPolyfills\Polyfills\ExpectExceptionMessageMatches;
17+
use Yoast\PHPUnitPolyfills\Polyfills\ExpectUserDeprecation;
1718

1819
/**
1920
* Basic test case for use with PHPUnit >= 8.
@@ -37,6 +38,7 @@ abstract class TestCase extends PHPUnit_TestCase {
3738
use AssertObjectProperty;
3839
use EqualToSpecializations;
3940
use ExpectExceptionMessageMatches;
41+
use ExpectUserDeprecation;
4042

4143
/**
4244
* This method is called before the first test of this test class is run.

0 commit comments

Comments
 (0)