Skip to content

Commit

Permalink
New Helpers\AssertAttributeHelper
Browse files Browse the repository at this point in the history
The PHPUnit `assertAttribute*()` methods were deprecated in PHPUnit 8.x and removed in PHPUnit 9.0.

Public properties can still be tested by accessing them directly.
Protected and private properties can no longer be tested using PHPUnit native functionality.

The reasoning for the removal of these assertion methods is that _private and protected properties are an implementation detail and should not be tested directly, but via methods in the class_.

It is strongly recommended to refactor tests, and if needs be, classes to adhere to this.

However, if for some reason the value of protected or private properties still needs to be tested, this helper can be used to get access to their properties and value.

Includes tests.

Fixes 2
  • Loading branch information
jrfnl committed Nov 25, 2020
1 parent e5a2e38 commit 45c6489
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 2 deletions.
37 changes: 35 additions & 2 deletions README.md
Expand Up @@ -13,6 +13,7 @@ Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit
* [Installation](#installation)
* [Features](#features)
- [Polyfill traits](#polyfill-traits)
- [Helper traits](#helper-traits)
- [TestCases](#testcases)
* [Using this library](#using-this-library)
* [Contributing](#contributing)
Expand Down Expand Up @@ -165,6 +166,38 @@ These methods were introduced in PHPUnit 9.1.0.
The original methods these new methods replace were hard deprecated in PHPUnit 9.1.0 and (will be) removed in PHPUnit 10.0.0.


### Helper traits

#### `Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper`

Helper to work around the removal of the `assertAttribute*()` methods.

The `assertAttribute*()` methods were deprecated in PHPUnit 8.x and removed in PHPUnit 9.0.

Public properties can still be tested by accessing them directly:
```php
$this->assertSame( 'value', $obj->propertyName );
```

Protected and private properties can no longer be tested using PHPUnit native functionality.
The reasoning for the removal of these assertion methods is that _private and protected properties are an implementation detail and should not be tested directly, but via methods in the class_.

It is strongly recommended to refactor your tests, and if needs be, your classes to adhere to this.

However, if for some reason the value of `protected` or `private` properties still needs to be tested, this helper can be used to get access to their value and attributes.

The trait contains two helper methods:
* `public static getProperty( object $classInstance, string $propertyName ) : ReflectionProperty`
* `public static getPropertyValue( object $classInstance, string $propertyName ) : mixed`

```php
// Test the value of a protected or private property.
$this->assertSame( 'value', $this->getPropertyValue( $objInstance, $propertyName ) );

// Retrieve a ReflectionProperty object to test other details of the property.
self::assertSame( $propertyName, self::getProperty( $objInstance, $propertyName )->getName() );
```

### TestCases

PHPUnit 8.0.0 introduced a `void` return type declaration to the "fixture" methods - `setUpBeforeClass()`, `setUp()`, `tearDown()` and `tearDownAfterClass()`.
Expand Down Expand Up @@ -278,7 +311,7 @@ class MyTest extends XTestCase {
Using this library
-------

Each of the polyfills has been setup as a trait and can be imported and `use`d in any test file which extends the PHPUnit native `TestCase` class.
Each of the polyfills and helpers has been setup as a trait and can be imported and `use`d in any test file which extends the PHPUnit native `TestCase` class.

If the polyfill is not needed for the particular PHPUnit version on which the tests are being run, the autoloader
will automatically load an empty trait with that same name, so you can safely use these traits in tests which
Expand Down Expand Up @@ -306,7 +339,7 @@ class FooTest extends TestCase

Alternatively, you can use one of the [`TestCase` classes](#testcases) provided by this library instead of using the PHPUnit native `TestCase` class.

In that case, all polyfills will be available whenever needed.
In that case, all polyfills and helpers will be available whenever needed.

```php
<?php
Expand Down
1 change: 1 addition & 0 deletions phpunitpolyfills-autoload.php
Expand Up @@ -65,6 +65,7 @@ public static function load( $class ) {

/*
* Handles:
* - Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper
* - Yoast\PHPUnitPolyfills\TestCases\XTestCase
*/
default:
Expand Down
70 changes: 70 additions & 0 deletions src/Helpers/AssertAttributeHelper.php
@@ -0,0 +1,70 @@
<?php

namespace Yoast\PHPUnitPolyfills\Helpers;

use ReflectionException;
use ReflectionObject;
use ReflectionProperty;

/**
* Helper to work-around the removal of the `assertAttribute*()` methods.
*
* The `assertAttribute*()` methods were deprecated in PHPUnit 8.x and
* removed in PHPUnit 9.0.
*
* Public properties can still be tested by accessing them directly:
* ```php
* $this->assertSame( 'value', $obj->propertyName );
* ```
*
* Protected and private properties can no longer be tested using PHPUnit native
* functionality.
* The reasoning for the removal of these assertion methods is that _private and
* protected properties are an implementation detail and should not be tested
* directly, but via methods in the class_.
*
* It is strongly recommended to refactor your tests, and if needs be, your classes
* to adhere to this.
*
* However, if for some reason the value of protected or private properties still
* needs to be tested, this helper can be used to get access to their value.
* ```php
* $this->assertSame( 'value', $this->getPropertyValue( $obj, $propertyName ) );
* ```
*
* @since 0.2.0
*/
trait AssertAttributeHelper {

/**
* Retrieve a private or protected property in an object.
*
* @param object $objInstance The object.
* @param string $propertyName The name of property to retrieve.
*
* @return ReflectionProperty
*
* @throws ReflectionException When a non-existent property is requested.
*/
public static function getProperty( $objInstance, $propertyName ) {
$reflect = new ReflectionObject( $objInstance );
$property = $reflect->getProperty( $propertyName );
$property->setAccessible( true );

return $property;
}

/**
* Retrieve the current value of a private or protected property in an object.
*
* @param object $objInstance The object.
* @param string $propertyName The name of property for which to retrieve the value.
*
* @return mixed
*/
public static function getPropertyValue( $objInstance, $propertyName ) {
$property = static::getProperty( $objInstance, $propertyName );

return $property->getValue( $objInstance );
}
}
2 changes: 2 additions & 0 deletions src/TestCases/TestCasePHPUnitGte8.php
Expand Up @@ -3,6 +3,7 @@
namespace Yoast\PHPUnitPolyfills\TestCases;

use PHPUnit\Framework\TestCase as PHPUnit_TestCase;
use Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
use Yoast\PHPUnitPolyfills\Polyfills\ExpectExceptionMessageMatches;
Expand All @@ -19,6 +20,7 @@
*/
abstract class TestCase extends PHPUnit_TestCase {

use AssertAttributeHelper;
use AssertFileEqualsSpecializations;
use AssertionRenames;
use ExpectExceptionMessageMatches;
Expand Down
2 changes: 2 additions & 0 deletions src/TestCases/TestCasePHPUnitLte7.php
Expand Up @@ -3,6 +3,7 @@
namespace Yoast\PHPUnitPolyfills\TestCases;

use PHPUnit\Framework\TestCase as PHPUnit_TestCase;
use Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper;
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
Expand All @@ -23,6 +24,7 @@
*/
abstract class TestCase extends PHPUnit_TestCase {

use AssertAttributeHelper;
use AssertEqualsSpecializations;
use AssertFileEqualsSpecializations;
use AssertionRenames;
Expand Down
2 changes: 2 additions & 0 deletions src/TestCases/XTestCase.php
Expand Up @@ -3,6 +3,7 @@
namespace Yoast\PHPUnitPolyfills\TestCases;

use PHPUnit\Framework\TestCase as PHPUnit_TestCase;
use Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper;
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
Expand All @@ -25,6 +26,7 @@
*/
abstract class XTestCase extends PHPUnit_TestCase {

use AssertAttributeHelper;
use AssertEqualsSpecializations;
use AssertFileEqualsSpecializations;
use AssertionRenames;
Expand Down
119 changes: 119 additions & 0 deletions tests/Helpers/AssertAttributesHelperTest.php
@@ -0,0 +1,119 @@
<?php

namespace Yoast\PHPUnitPolyfills\Tests\Helpers;

use ReflectionException;
use Yoast\PHPUnitPolyfills\TestCases\TestCase;
use Yoast\PHPUnitPolyfills\Tests\Helpers\Fixtures\ClassWithProperties;

/**
* Test the helper methods in the AssertAttributeHelper trait.
*
* @covers \Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper
*/
class AssertAttributesHelperTest extends TestCase {

/**
* Instance of the ClassWithProperties class.
*
* @var ClassWithProperties
*/
public $instance;

/**
* Set up the class under test.
*
* @return void
*/
protected function set_up() {
$this->instance = new ClassWithProperties();
}

/**
* Test retrieving information on the public property in its original state.
*
* @return void
*/
public function testOriginalStatePublicProperty() {
$this->assertNull( $this->instance->public_prop );
$this->assertNull( $this->getPropertyValue( $this->instance, 'public_prop' ) );
$this->assertTrue( $this->getProperty( $this->instance, 'public_prop' )->isDefault() );
}

/**
* Test retrieving information on the protected property in its original state.
*
* @return void
*/
public function testOriginalStateProtectedProperty() {
$this->assertNull( self::getPropertyValue( $this->instance, 'protected_prop' ) );
$this->assertTrue( $this->getProperty( $this->instance, 'protected_prop' )->isDefault() );
}

/**
* Test retrieving information on the private property in its original state.
*
* @return void
*/
public function testOriginalStatePrivateProperty() {
$this->assertFalse( $this->getPropertyValue( $this->instance, 'private_prop' ) );
$this->assertTrue( static::getProperty( $this->instance, 'private_prop' )->isDefault() );
}

/**
* Test receiving an exception for a non-existent dynamic property.
*
* @return void
*/
public function testOriginalStateDynamicProperty() {
$this->expectException( ReflectionException::class );

$this->getPropertyValue( $this->instance, 'dynamic' );
}

/**
* Test retrieving information on the public property once it has been set.
*
* @return void
*/
public function testPropertyValueOnceSetPublicProperty() {
$this->instance->setProperties();

$this->assertSame( 'public', $this->instance->public_prop );
$this->assertSame( 'public', $this->getPropertyValue( $this->instance, 'public_prop' ) );
}

/**
* Test retrieving information on the protected property once it has been set.
*
* @return void
*/
public function testPropertyValueOnceSetProtectedProperty() {
$this->instance->setProperties();

$this->assertSame( 100, $this->getPropertyValue( $this->instance, 'protected_prop' ) );
}

/**
* Test retrieving information on the private property once it has been set.
*
* @return void
*/
public function testPropertyValueOnceSetPrivateProperty() {
$this->instance->setProperties();

$this->assertTrue( $this->getPropertyValue( $this->instance, 'private_prop' ) );
}

/**
* Test retrieving information on the dynamic property once it has been set.
*
* @return void
*/
public function testPropertyValueOnceSetDynamicProperty() {
$this->instance->setProperties();

$this->assertInstanceOf( ClassWithProperties::class, $this->getPropertyValue( $this->instance, 'dynamic' ) );
$this->assertFalse( $this->getProperty( $this->instance, 'dynamic' )->isDefault() );
}
}
44 changes: 44 additions & 0 deletions tests/Helpers/Fixtures/ClassWithProperties.php
@@ -0,0 +1,44 @@
<?php

namespace Yoast\PHPUnitPolyfills\Tests\Helpers\Fixtures;

/**
* Fixture to test the AssertAttributeHelper.
*/
class ClassWithProperties {

/**
* Public property.
*
* @var string|null
*/
public $public_prop = null;

/**
* Protected property.
*
* @var int|null
*/
protected $protected_prop;

/**
* Private property.
*
* @var bool
*/
private $private_prop = false;

/**
* Set values for the properties to allow for testing the AssertAttributeHelper.
*
* @return void
*/
public function setProperties() {
$this->public_prop = 'public';
$this->protected_prop = 100;
$this->private_prop = true;

// Set a non-predefined property.
$this->dynamic = new self();
}
}

0 comments on commit 45c6489

Please sign in to comment.