Skip to content

Commit

Permalink
Merge pull request #44 from Yoast/develop
Browse files Browse the repository at this point in the history
Release version 1.1.0
  • Loading branch information
jrfnl authored Nov 16, 2022
2 parents 21df3a0 + 5872af5 commit f319edb
Show file tree
Hide file tree
Showing 14 changed files with 815 additions and 45 deletions.
29 changes: 29 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Dependabot configuration.
#
# Please see the documentation for all configuration options:
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
# Maintain dependencies for GitHub Actions.
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
commit-message:
prefix: "GH Actions:"
labels:
- "yoastcs/qa"

# Maintain dependencies for Composer.
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5 # Set to 0 to (temporarily) disable.
versioning-strategy: "increase-if-necessary"
commit-message:
prefix: "Composer:"
labels:
- "yoastcs/qa"
10 changes: 7 additions & 3 deletions .github/workflows/cs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3

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

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

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

- name: Show PHPCS results in PR
if: ${{ always() && steps.phpcs.outcome == 'failure' }}
run: cs2pr ./phpcs-report.xml
24 changes: 6 additions & 18 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,13 @@ jobs:

strategy:
matrix:
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
experimental: [false]

include:
- php: '8.1'
experimental: true
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2']

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

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

steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Install PHP
uses: shivammathur/setup-php@v2
Expand All @@ -38,16 +31,11 @@ jobs:

# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-composer-dependencies
- name: Install Composer dependencies for PHP < 8.1
if: ${{ matrix.php < 8.1 }}
uses: "ramsey/composer-install@v1"

# For PHP 8.1 and above, we need to install with ignore platform reqs as not all dependencies allow it yet.
- name: Install Composer dependencies for PHP >= 8.1
if: ${{ matrix.php >= 8.1 }}
uses: "ramsey/composer-install@v1"
- name: Install Composer dependencies
uses: "ramsey/composer-install@v2"
with:
composer-options: --ignore-platform-reqs
# Bust the cache at least once a month - output format: YYYY-MM-DD.
custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F")

- name: Lint PHP files against parse errors
run: composer lint
Expand Down
18 changes: 6 additions & 12 deletions .phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,18 @@

<!-- Allow for camelCase method and variable names to be more in line with PHPUnit and BrainMonkey. -->
<rule ref="WordPress.NamingConventions.ValidFunctionName">
<exclude-pattern>/src/BrainMonkey/bootstrap\.php$</exclude-pattern>
<exclude-pattern>/src/Helpers/*\.php$</exclude-pattern>
</rule>
<rule ref="WordPress.NamingConventions.ValidVariableName">
<exclude-pattern>/src/Helpers/*\.php$</exclude-pattern>
</rule>

<!-- This class is not a test double for the tests, but a _feature_ of this package. -->
<rule ref="Yoast.Files.TestDoubles">
<exclude-pattern>/src/BrainMonkey/Doubles/DummyTestDouble\.php$</exclude-pattern>
</rule>

<!-- Ignore word count for object names in tests. -->
<rule ref="Yoast.NamingConventions.ObjectNameDepth.MaxExceeded">
<exclude-pattern>/tests/*\.php$</exclude-pattern>
Expand All @@ -125,16 +131,4 @@
<exclude-pattern>/tests/*/Fixtures/*\.php$</exclude-pattern>
</rule>

<!--
#############################################################################
TEMPORARY ADJUSTMENTS
Adjustments which should be removed once the associated issue has been resolved.
#############################################################################
-->

<!-- PHPCS Bug: https://github.com/squizlabs/PHP_CodeSniffer/pull/3184 -->
<rule ref="PSR2.Namespaces.NamespaceDeclaration">
<exclude-pattern>/src/WPIntegration/(bootstrap-functions|Autoload)\.php$</exclude-pattern>
</rule>

</ruleset>
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses

_Nothing yet._

## [1.1.0] - 2022-11-17

### Added
* Helper functions for on-the-fly creation of opaque test doubles for unavailable classes for use with Mockery. PR [#40]
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.
These helper functions can be used to create test doubles which do allow for setting properties.
The helper functions can be called from within a test bootstrap or from within a test class.
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).

### Changed
* 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]
* 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]
* Composer: The package will now identify itself as a testing tool. PR [#36]
* Verified PHP 8.2 compatibility.
* General housekeeping.

[#28]: https://github.com/Yoast/wp-test-utils/pull/28
[#36]: https://github.com/Yoast/wp-test-utils/pull/36
[#40]: https://github.com/Yoast/wp-test-utils/pull/40
[#41]: https://github.com/Yoast/wp-test-utils/pull/41


## [1.0.0] - 2021-09-27

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


[Unreleased]: https://github.com/Yoast/wp-test-utils/compare/main...HEAD
[1.1.0]: https://github.com/Yoast/wp-test-utils/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/Yoast/wp-test-utils/compare/0.2.2...1.0.0
[0.2.2]: https://github.com/Yoast/wp-test-utils/compare/0.2.1...0.2.2
[0.2.1]: https://github.com/Yoast/wp-test-utils/compare/0.2.0...0.2.1
Expand Down
80 changes: 76 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ WP Test Utils
[![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)
[![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)
[![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)
[![License: BSD3](https://poser.pugx.org/yoast/wp-test-utils/license)](https://github.com/Yoast/wp-test-utils/blob/master/LICENSE)
[![License: BSD3](https://poser.pugx.org/yoast/wp-test-utils/license)](https://github.com/Yoast/wp-test-utils/blob/main/LICENSE)

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

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

The following packages will be automatically required via Composer:
* [PHPUnit Polyfills] 1.0.1 or higher.
* [PHPUnit Polyfills] 1.0.4 or higher.
* [PHPUnit] 5.7 - 9.x.
* [BrainMonkey] 2.6.0 or higher.
* [BrainMonkey] 2.6.1 or higher.


Installation
Expand Down Expand Up @@ -67,7 +68,8 @@ Features of this `TestCase`:
The BrainMonkey native functions create stubs which will apply basic HTML escaping if the stubbed function is an escaping function, like `esc_html__()`.<br/>
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/>
_Note: the alternative implementation should be used selectively._
5. Helper functions for setting expectations for generated output.
5. Helper functions for [setting expectations for generated output](#yoastwptestutilshelpersescapeoutputhelper-trait).
6. Helper functions for [creating "dummy" test doubles for unavailable classes](#helpers-to-create-test-doubles-for-unavailable-classes).

**_Implementation example:_**
```php
Expand Down Expand Up @@ -168,6 +170,76 @@ require_once dirname( __DIR__ ) . '/vendor/autoload.php';
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.


#### Helpers to create test doubles for unavailable classes

##### Why you may need to create test doubles for unavailable classes

Typically a mock for an unavailable class is created using `Mockery::mock()` or `Mockery::mock( 'Unavailable' )`.

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.

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.

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).

##### How to use the functionality

WP Test Utils offers three new utilities to solve this (as of version 1.1.0).
* `Yoast\WPTestUtils\BrainMonkey\makeDoublesForUnavailableClasses( array $class_names )` for use from within a test bootstrap file.
* `Yoast\WPTestUtils\BrainMonkey\TestCase::makeDoublesForUnavailableClasses( array $class_names )` and `Yoast\WPTestUtils\BrainMonkey\TestCase::makeDoubleForUnavailableClass( string $class_name )` for use from within a test class.

These methods can be used to create one or more "fake" test double classes on the fly, which allow for setting (dynamic) properties.
These "fake" test double classes are effectively aliases for `stdClass`.

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.

For setting expectations on the "fake" test double, use `Mockery::mock( 'FakedClass' )`.

**_Implementation example using the bootstrap function:_**

You can create the "fake" test doubles for a complete test suite in one go in your test bootstrap file like so:

```php
<?php
// File: tests/bootstrap.php
require_once dirname( __DIR__ ) . '/vendor/yoast/wp-test-utils/src/BrainMonkey/bootstrap.php';
require_once dirname( __DIR__ ) . '/vendor/autoload.php';

Yoast\WPTestUtils\BrainMonkey\makeDoublesForUnavailableClasses( [ 'WP_Post', 'wpdb' ] );
```

**_Implementation example using these functions from within a test class:_**

Alternatively, you can create the "fake" test double(s) last minute in each test class which needs them.

```php
<?php
namespace PackageName\Tests;

use Mockery;
use WP_Post;
use wpdb;
use Yoast\WPTestUtils\BrainMonkey\TestCase;

class FooTest extends TestCase {
protected function set_up_before_class() {
parent::set_up_before_class();
self::makeDoublesForUnavailableClasses( [ WP_Post::class, wpdb::class ] );
// or if only one class is needed:
self::makeDoubleForUnavailableClass( WP_Post::class );
}

public function testSomethingWhichUsesWpPost() {
$wp_post = Mockery::mock( WP_Post::class );
$wp_post->post_title = 'my test title';
$wp_post->post_type = 'my_custom_type';

$this->assertSame( 'expected', \function_under_test( $wp_post ) );
}
}
```


### Utilities for running integration tests with WordPress

#### What these utilities solve
Expand Down
15 changes: 10 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name" : "yoast/wp-test-utils",
"description" : "PHPUnit cross-version compatibility layer for testing plugins and themes build for WordPress",
"keywords" : [ "wordpress", "unit-testing", "integration-testing", "brainmonkey", "phpunit" ],
"keywords" : [ "wordpress", "unit-testing", "integration-testing", "brainmonkey", "phpunit", "testing" ],
"license" : "BSD-3-Clause",
"homepage": "https://github.com/Yoast/wp-test-utils/",
"authors": [
Expand All @@ -21,11 +21,16 @@
},
"require" : {
"php" : ">=5.6",
"yoast/phpunit-polyfills": "^1.0.1",
"brain/monkey": "^2.6.0"
"yoast/phpunit-polyfills": "^1.0.4",
"brain/monkey": "^2.6.1"
},
"require-dev" : {
"yoast/yoastcs": "^2.2.0"
"yoast/yoastcs": "^2.2.1"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"minimum-stability": "dev",
"prefer-stable": true,
Expand All @@ -51,7 +56,7 @@
},
"scripts" : {
"lint": [
"@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git"
"@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git"
],
"check-cs": [
"@php ./vendor/squizlabs/php_codesniffer/bin/phpcs"
Expand Down
38 changes: 38 additions & 0 deletions src/BrainMonkey/Doubles/DummyTestDouble.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Yoast\WPTestUtils\BrainMonkey\Doubles;

use stdClass;

/**
* This is a "dummy" test double class for use with Mockery.
*
* This class allows to mock classes which are unavailable during the test run
* and on which properties need to be set, either from within the test or
* from within the code under test, by aliasing this class ahead of creating the mock.
*
* Mocking unavailable classes using an anonymous mock - `Mockery::mock()` or
* a mock for a specific named, but unavailable class - `Mockery::mock( 'Unavailable' )` -
* worked fine prior to PHP 8.2.
* However, PHP 8.2 deprecates the use of dynamic properties, which means that if
* either of the above code patterns is used and either the test or the code under
* test sets properties on the Mock, tests will throw deprecation notices and,
* depending on the value for the PHPUnit `convertDeprecationsToExceptions` configuration
* option, tests may show as errored.
*
* The "go to" pattern to solve this is to let the mock extend `stdClass`, but
* as `stdClass` always exists, the class will then identify as an instance of `stdClass`
* and no longer as an instance of the "Unavailable" class, which causes problems
* with code using type declarations of calls to `instanceof`.
*
* The other alternative would be to used `Mockery::namedMock()` or an alias mock, but
* both of these require each test using these to run in a separate process, which
* makes debugging of failing tests more complicated as well as making the test suite
* slower.
*
* Note: aliasing `stdClass` directly is not allowed in PHP, which is why this
* dummy test double class is put in place.
*
* @link https://github.com/mockery/mockery/issues/1197
*/
class DummyTestDouble extends stdClass {}
Loading

0 comments on commit f319edb

Please sign in to comment.