Skip to content

Commit f319edb

Browse files
authored
Merge pull request #44 from Yoast/develop
Release version 1.1.0
2 parents 21df3a0 + 5872af5 commit f319edb

File tree

14 files changed

+815
-45
lines changed

14 files changed

+815
-45
lines changed

.github/dependabot.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Dependabot configuration.
2+
#
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
# Maintain dependencies for GitHub Actions.
9+
- package-ecosystem: "github-actions"
10+
directory: "/"
11+
schedule:
12+
interval: "weekly"
13+
open-pull-requests-limit: 5
14+
commit-message:
15+
prefix: "GH Actions:"
16+
labels:
17+
- "yoastcs/qa"
18+
19+
# Maintain dependencies for Composer.
20+
- package-ecosystem: "composer"
21+
directory: "/"
22+
schedule:
23+
interval: "weekly"
24+
open-pull-requests-limit: 5 # Set to 0 to (temporarily) disable.
25+
versioning-strategy: "increase-if-necessary"
26+
commit-message:
27+
prefix: "Composer:"
28+
labels:
29+
- "yoastcs/qa"

.github/workflows/cs.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
steps:
1616
- name: Checkout code
17-
uses: actions/checkout@v2
17+
uses: actions/checkout@v3
1818

1919
- name: Install PHP
2020
uses: shivammathur/setup-php@v2
@@ -26,7 +26,10 @@ jobs:
2626
# Install dependencies and handle caching in one go.
2727
# @link https://github.com/marketplace/actions/install-composer-dependencies
2828
- name: Install Composer dependencies
29-
uses: "ramsey/composer-install@v1"
29+
uses: "ramsey/composer-install@v2"
30+
with:
31+
# Bust the cache at least once a month - output format: YYYY-MM-DD.
32+
custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F")
3033

3134
# Validate the composer.json file.
3235
# @link https://getcomposer.org/doc/03-cli.md#validate
@@ -35,8 +38,9 @@ jobs:
3538

3639
# Check the code-style consistency of the PHP files.
3740
- name: Check PHP code style
38-
continue-on-error: true
41+
id: phpcs
3942
run: composer check-cs -- --report-full --report-checkstyle=./phpcs-report.xml
4043

4144
- name: Show PHPCS results in PR
45+
if: ${{ always() && steps.phpcs.outcome == 'failure' }}
4246
run: cs2pr ./phpcs-report.xml

.github/workflows/test.yml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,13 @@ jobs:
1414

1515
strategy:
1616
matrix:
17-
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
18-
experimental: [false]
19-
20-
include:
21-
- php: '8.1'
22-
experimental: true
17+
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2']
2318

2419
name: "Tests: PHP ${{ matrix.php }}"
2520

26-
continue-on-error: ${{ matrix.experimental }}
27-
2821
steps:
2922
- name: Checkout code
30-
uses: actions/checkout@v2
23+
uses: actions/checkout@v3
3124

3225
- name: Install PHP
3326
uses: shivammathur/setup-php@v2
@@ -38,16 +31,11 @@ jobs:
3831

3932
# Install dependencies and handle caching in one go.
4033
# @link https://github.com/marketplace/actions/install-composer-dependencies
41-
- name: Install Composer dependencies for PHP < 8.1
42-
if: ${{ matrix.php < 8.1 }}
43-
uses: "ramsey/composer-install@v1"
44-
45-
# For PHP 8.1 and above, we need to install with ignore platform reqs as not all dependencies allow it yet.
46-
- name: Install Composer dependencies for PHP >= 8.1
47-
if: ${{ matrix.php >= 8.1 }}
48-
uses: "ramsey/composer-install@v1"
34+
- name: Install Composer dependencies
35+
uses: "ramsey/composer-install@v2"
4936
with:
50-
composer-options: --ignore-platform-reqs
37+
# Bust the cache at least once a month - output format: YYYY-MM-DD.
38+
custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F")
5139

5240
- name: Lint PHP files against parse errors
5341
run: composer lint

.phpcs.xml.dist

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,18 @@
109109

110110
<!-- Allow for camelCase method and variable names to be more in line with PHPUnit and BrainMonkey. -->
111111
<rule ref="WordPress.NamingConventions.ValidFunctionName">
112+
<exclude-pattern>/src/BrainMonkey/bootstrap\.php$</exclude-pattern>
112113
<exclude-pattern>/src/Helpers/*\.php$</exclude-pattern>
113114
</rule>
114115
<rule ref="WordPress.NamingConventions.ValidVariableName">
115116
<exclude-pattern>/src/Helpers/*\.php$</exclude-pattern>
116117
</rule>
117118

119+
<!-- This class is not a test double for the tests, but a _feature_ of this package. -->
120+
<rule ref="Yoast.Files.TestDoubles">
121+
<exclude-pattern>/src/BrainMonkey/Doubles/DummyTestDouble\.php$</exclude-pattern>
122+
</rule>
123+
118124
<!-- Ignore word count for object names in tests. -->
119125
<rule ref="Yoast.NamingConventions.ObjectNameDepth.MaxExceeded">
120126
<exclude-pattern>/tests/*\.php$</exclude-pattern>
@@ -125,16 +131,4 @@
125131
<exclude-pattern>/tests/*/Fixtures/*\.php$</exclude-pattern>
126132
</rule>
127133

128-
<!--
129-
#############################################################################
130-
TEMPORARY ADJUSTMENTS
131-
Adjustments which should be removed once the associated issue has been resolved.
132-
#############################################################################
133-
-->
134-
135-
<!-- PHPCS Bug: https://github.com/squizlabs/PHP_CodeSniffer/pull/3184 -->
136-
<rule ref="PSR2.Namespaces.NamespaceDeclaration">
137-
<exclude-pattern>/src/WPIntegration/(bootstrap-functions|Autoload)\.php$</exclude-pattern>
138-
</rule>
139-
140134
</ruleset>

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@ This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses
99

1010
_Nothing yet._
1111

12+
## [1.1.0] - 2022-11-17
13+
14+
### Added
15+
* Helper functions for on-the-fly creation of opaque test doubles for unavailable classes for use with Mockery. PR [#40]
16+
The default Mockery mocks for unavailable classes do not allow for the dynamic property deprecation in PHP 8.2, which can cause tests to error out.
17+
These helper functions can be used to create test doubles which do allow for setting properties.
18+
The helper functions can be called from within a test bootstrap or from within a test class.
19+
For full details about these new functions, why they exist and how to use them, please see [the documentation in the README](https://github.com/Yoast/wp-test-utils#helpers-to-create-test-doubles-for-unavailable-classes).
20+
21+
### Changed
22+
* The [BrainMonkey] dependency has been updated to require [version `^2.6.1`](https://github.com/Brain-WP/BrainMonkey/releases/tag/2.6.1) (was `^2.6.0`). PR [#28]
23+
* The [PHPUnit Polyfills] dependency has been updated to require [version `^1.0.4`](https://github.com/Yoast/PHPUnit-Polyfills/releases/tag/1.0.4) (was `^1.0.1`). PRs [#28], [#41]
24+
* Composer: The package will now identify itself as a testing tool. PR [#36]
25+
* Verified PHP 8.2 compatibility.
26+
* General housekeeping.
27+
28+
[#28]: https://github.com/Yoast/wp-test-utils/pull/28
29+
[#36]: https://github.com/Yoast/wp-test-utils/pull/36
30+
[#40]: https://github.com/Yoast/wp-test-utils/pull/40
31+
[#41]: https://github.com/Yoast/wp-test-utils/pull/41
32+
33+
1234
## [1.0.0] - 2021-09-27
1335

1436
WordPress 5.9 contains significant changes to the WordPress native test suite, which impacts **integration tests**.<br/>
@@ -86,6 +108,7 @@ Initial release.
86108

87109

88110
[Unreleased]: https://github.com/Yoast/wp-test-utils/compare/main...HEAD
111+
[1.1.0]: https://github.com/Yoast/wp-test-utils/compare/1.0.0...1.1.0
89112
[1.0.0]: https://github.com/Yoast/wp-test-utils/compare/0.2.2...1.0.0
90113
[0.2.2]: https://github.com/Yoast/wp-test-utils/compare/0.2.1...0.2.2
91114
[0.2.1]: https://github.com/Yoast/wp-test-utils/compare/0.2.0...0.2.1

README.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ WP Test Utils
55
[![CS Build Status](https://github.com/Yoast/wp-test-utils/actions/workflows/cs.yml/badge.svg)](https://github.com/Yoast/wp-test-utils/actions/workflows/cs.yml)
66
[![Test Build Status](https://github.com/Yoast/wp-test-utils/actions/workflows/test.yml/badge.svg)](https://github.com/Yoast/wp-test-utils/actions/workflows/test.yml)
77
[![Minimum PHP Version](https://img.shields.io/packagist/php-v/yoast/wp-test-utils.svg?maxAge=3600)](https://packagist.org/packages/yoast/wp-test-utils)
8-
[![License: BSD3](https://poser.pugx.org/yoast/wp-test-utils/license)](https://github.com/Yoast/wp-test-utils/blob/master/LICENSE)
8+
[![License: BSD3](https://poser.pugx.org/yoast/wp-test-utils/license)](https://github.com/Yoast/wp-test-utils/blob/main/LICENSE)
99

1010
This library contains a set of utilities for running automated tests for WordPress plugins and themes.
1111

@@ -16,6 +16,7 @@ This library contains a set of utilities for running automated tests for WordPre
1616
- [Basic `TestCase` for use with BrainMonkey](#basic-testcase-for-use-with-brainmonkey)
1717
- [Yoast TestCase for use with BrainMonkey](#yoast-testcase-for-use-with-brainmonkey)
1818
- [Bootstrap file for use with BrainMonkey](#bootstrap-file-for-use-with-brainmonkey)
19+
- [Helpers to create test doubles for unavailable classes](#helpers-to-create-test-doubles-for-unavailable-classes)
1920
- [Utilities for running integration tests with WordPress](#utilities-for-running-integration-tests-with-wordpress)
2021
- [What these utilities solve](#what-these-utilities-solve)
2122
- [Basic `TestCase` for WordPress integration tests](#basic-testcase-for-wordpress-integration-tests)
@@ -32,9 +33,9 @@ Requirements
3233
* PHP 5.6 or higher.
3334

3435
The following packages will be automatically required via Composer:
35-
* [PHPUnit Polyfills] 1.0.1 or higher.
36+
* [PHPUnit Polyfills] 1.0.4 or higher.
3637
* [PHPUnit] 5.7 - 9.x.
37-
* [BrainMonkey] 2.6.0 or higher.
38+
* [BrainMonkey] 2.6.1 or higher.
3839

3940

4041
Installation
@@ -67,7 +68,8 @@ Features of this `TestCase`:
6768
The BrainMonkey native functions create stubs which will apply basic HTML escaping if the stubbed function is an escaping function, like `esc_html__()`.<br/>
6869
The alternative implementations of these functions will create stubs which will return the original value without change. This makes creating tests easier as the `$expected` value does not need to account for the HTML escaping.<br/>
6970
_Note: the alternative implementation should be used selectively._
70-
5. Helper functions for setting expectations for generated output.
71+
5. Helper functions for [setting expectations for generated output](#yoastwptestutilshelpersescapeoutputhelper-trait).
72+
6. Helper functions for [creating "dummy" test doubles for unavailable classes](#helpers-to-create-test-doubles-for-unavailable-classes).
7173

7274
**_Implementation example:_**
7375
```php
@@ -168,6 +170,76 @@ require_once dirname( __DIR__ ) . '/vendor/autoload.php';
168170
To tell PHPUnit to use this bootstrap file, use `--bootstrap tests/bootstrap.php` on the command-line or add the `bootstrap="tests/bootstrap.php"` attribute to your `phpunit.xml.dist` file.
169171

170172

173+
#### Helpers to create test doubles for unavailable classes
174+
175+
##### Why you may need to create test doubles for unavailable classes
176+
177+
Typically a mock for an unavailable class is created using `Mockery::mock()` or `Mockery::mock( 'Unavailable' )`.
178+
179+
When either the test or the code under test sets a property on such a mock, this will lead to a ["Creation of dynamic properties is deprecated" notice](https://wiki.php.net/rfc/deprecate_dynamic_properties) on PHP >= 8.2, which can cause tests to error out.
180+
181+
If you know for sure the property being set on the mock is a declared property or a property supported via [magic methods](https://www.php.net/oop5.overloading#language.oop5.overloading.members) on the class which is being mocked, the _code under test_ will under normal circumstances never lead to this deprecation notice, but your tests now do.
182+
183+
Primarly this is an issue with Mockery. A [question on how to handle this/to add support for this in Mockery itself](https://github.com/mockery/mockery/issues/1197) is open, but in the mean time a work-around is needed (if you're interested, have a read through the Mockery issue for details about alternative solutions and why those don't work as intended).
184+
185+
##### How to use the functionality
186+
187+
WP Test Utils offers three new utilities to solve this (as of version 1.1.0).
188+
* `Yoast\WPTestUtils\BrainMonkey\makeDoublesForUnavailableClasses( array $class_names )` for use from within a test bootstrap file.
189+
* `Yoast\WPTestUtils\BrainMonkey\TestCase::makeDoublesForUnavailableClasses( array $class_names )` and `Yoast\WPTestUtils\BrainMonkey\TestCase::makeDoubleForUnavailableClass( string $class_name )` for use from within a test class.
190+
191+
These methods can be used to create one or more "fake" test double classes on the fly, which allow for setting (dynamic) properties.
192+
These "fake" test double classes are effectively aliases for `stdClass`.
193+
194+
These methods are solely intended for classes which are unavailable during the test run and have no effect (at all!) on classes which _are_ available during the test run.
195+
196+
For setting expectations on the "fake" test double, use `Mockery::mock( 'FakedClass' )`.
197+
198+
**_Implementation example using the bootstrap function:_**
199+
200+
You can create the "fake" test doubles for a complete test suite in one go in your test bootstrap file like so:
201+
202+
```php
203+
<?php
204+
// File: tests/bootstrap.php
205+
require_once dirname( __DIR__ ) . '/vendor/yoast/wp-test-utils/src/BrainMonkey/bootstrap.php';
206+
require_once dirname( __DIR__ ) . '/vendor/autoload.php';
207+
208+
Yoast\WPTestUtils\BrainMonkey\makeDoublesForUnavailableClasses( [ 'WP_Post', 'wpdb' ] );
209+
```
210+
211+
**_Implementation example using these functions from within a test class:_**
212+
213+
Alternatively, you can create the "fake" test double(s) last minute in each test class which needs them.
214+
215+
```php
216+
<?php
217+
namespace PackageName\Tests;
218+
219+
use Mockery;
220+
use WP_Post;
221+
use wpdb;
222+
use Yoast\WPTestUtils\BrainMonkey\TestCase;
223+
224+
class FooTest extends TestCase {
225+
protected function set_up_before_class() {
226+
parent::set_up_before_class();
227+
self::makeDoublesForUnavailableClasses( [ WP_Post::class, wpdb::class ] );
228+
// or if only one class is needed:
229+
self::makeDoubleForUnavailableClass( WP_Post::class );
230+
}
231+
232+
public function testSomethingWhichUsesWpPost() {
233+
$wp_post = Mockery::mock( WP_Post::class );
234+
$wp_post->post_title = 'my test title';
235+
$wp_post->post_type = 'my_custom_type';
236+
237+
$this->assertSame( 'expected', \function_under_test( $wp_post ) );
238+
}
239+
}
240+
```
241+
242+
171243
### Utilities for running integration tests with WordPress
172244

173245
#### What these utilities solve

composer.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name" : "yoast/wp-test-utils",
33
"description" : "PHPUnit cross-version compatibility layer for testing plugins and themes build for WordPress",
4-
"keywords" : [ "wordpress", "unit-testing", "integration-testing", "brainmonkey", "phpunit" ],
4+
"keywords" : [ "wordpress", "unit-testing", "integration-testing", "brainmonkey", "phpunit", "testing" ],
55
"license" : "BSD-3-Clause",
66
"homepage": "https://github.com/Yoast/wp-test-utils/",
77
"authors": [
@@ -21,11 +21,16 @@
2121
},
2222
"require" : {
2323
"php" : ">=5.6",
24-
"yoast/phpunit-polyfills": "^1.0.1",
25-
"brain/monkey": "^2.6.0"
24+
"yoast/phpunit-polyfills": "^1.0.4",
25+
"brain/monkey": "^2.6.1"
2626
},
2727
"require-dev" : {
28-
"yoast/yoastcs": "^2.2.0"
28+
"yoast/yoastcs": "^2.2.1"
29+
},
30+
"config": {
31+
"allow-plugins": {
32+
"dealerdirect/phpcodesniffer-composer-installer": true
33+
}
2934
},
3035
"minimum-stability": "dev",
3136
"prefer-stable": true,
@@ -51,7 +56,7 @@
5156
},
5257
"scripts" : {
5358
"lint": [
54-
"@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git"
59+
"@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git"
5560
],
5661
"check-cs": [
5762
"@php ./vendor/squizlabs/php_codesniffer/bin/phpcs"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Yoast\WPTestUtils\BrainMonkey\Doubles;
4+
5+
use stdClass;
6+
7+
/**
8+
* This is a "dummy" test double class for use with Mockery.
9+
*
10+
* This class allows to mock classes which are unavailable during the test run
11+
* and on which properties need to be set, either from within the test or
12+
* from within the code under test, by aliasing this class ahead of creating the mock.
13+
*
14+
* Mocking unavailable classes using an anonymous mock - `Mockery::mock()` or
15+
* a mock for a specific named, but unavailable class - `Mockery::mock( 'Unavailable' )` -
16+
* worked fine prior to PHP 8.2.
17+
* However, PHP 8.2 deprecates the use of dynamic properties, which means that if
18+
* either of the above code patterns is used and either the test or the code under
19+
* test sets properties on the Mock, tests will throw deprecation notices and,
20+
* depending on the value for the PHPUnit `convertDeprecationsToExceptions` configuration
21+
* option, tests may show as errored.
22+
*
23+
* The "go to" pattern to solve this is to let the mock extend `stdClass`, but
24+
* as `stdClass` always exists, the class will then identify as an instance of `stdClass`
25+
* and no longer as an instance of the "Unavailable" class, which causes problems
26+
* with code using type declarations of calls to `instanceof`.
27+
*
28+
* The other alternative would be to used `Mockery::namedMock()` or an alias mock, but
29+
* both of these require each test using these to run in a separate process, which
30+
* makes debugging of failing tests more complicated as well as making the test suite
31+
* slower.
32+
*
33+
* Note: aliasing `stdClass` directly is not allowed in PHP, which is why this
34+
* dummy test double class is put in place.
35+
*
36+
* @link https://github.com/mockery/mockery/issues/1197
37+
*/
38+
class DummyTestDouble extends stdClass {}

0 commit comments

Comments
 (0)