PHPUnit Test Private Property and Method Feature Sample

  • 2021-10-16 01:17:55
  • OfStack

This article illustrates the PHPUnit test private properties and method functionality. Share it for your reference, as follows:

1. Test private methods in a class:


class Sample
{
  private $a = 0;
  private function run()
  {
    echo $a;
  }
}

The above simply writes 1 class contain, 1 private variable and 1 private method. For protected and private methods, because they can't be called directly like public method 1, it is inconvenient to use phpunit for single test, especially when only a few interfaces are provided externally and a large number of private methods are used internally in a class.

For the protected method, it is recommended to use inheritance for testing, which will not be repeated here. For the test of private method, it is recommended to use the reflection mechanism of php. Without saying much, put on the code:


class testSample()
{
    $method = new ReflectionMethod('Sample', 'run');
    $method->setAccessible(true); // Will run Method is derived from the private Become similar to public Permissions of 
    $method->invoke(new Sample()); // Call run Method 
}

If the run method is static, such as:


private static function run()
{
  echo 'run is a private static function';
}

Then the invoke function can also be written as follows:


$method->invoke(null); // Only static methods can be instantiated without passing classes 

If run also needs to pass parameters, such as:


private function run($x, $y)
{
  return $x + $y;
}

Then, the test code can be changed to:


$method->invokeArgs(new Sample(), array(1, 2));
//array Write the parameters to be passed in turn. Execution result returns 3

"Note": It is good to test private methods using reflection, but the setAccessible function is supported after php version 5.3. 2 ( > = 5.3. 2)

2. get/set for private properties

Having finished the private method, let's look at the private property again. Still take the Sample class as an example. To get or set the value of the private property $a in the Sample class, you can use the following methods:


public function testPrivateProperty()
{
  $reflectedClass = new ReflectionClass('Sample');
  $reflectedProperty = $reflectedClass->getProperty('a');
  $reflectedProperty->setAccessible(true);
  $reflectedProperty->getValue(); // Get $a Value of 
  $reflectedProperty->setValue(123); // To $a Assignment :$a = 123;
}

The above method is still valid for static attributes.

At this point, do you instantly feel that it is easy to test private methods or properties?

Attachment: PHPunit test private method (English original)

This article is part of a series on testing untestable code:

Testing private methods Testing code that uses singletons Stubbing static methods Stubbing hard-coded dependencies

No, not those privates. If you need help with those, this book might help.

One question I get over and over again when talking about Unit Testing is this:

"How do I test the private attributes and methods of my objects?"

Lets assume we have a class Foo:


<?php
class Foo
{
  private $bar = 'baz';
  public function doSomething()
  {
    return $this->bar = $this->doSomethingPrivate();
  }
  private function doSomethingPrivate()
  {
    return 'blah';
  }
}
?>

Before we explore how protected and private attributes and methods can be tested directly, lets have a look at how they can be tested indirectly.

The following test calls the testDoSomething() method which in turn calls thedoSomethingPrivate() method:


<?php
class FooTest extends PHPUnit_Framework_TestCase
{
  /**
   * @covers Foo::doSomething
   * @covers Foo::doSomethingPrivate
   */
  public function testDoSomething()
  {
    $foo = new Foo;
    $this->assertEquals('blah', $foo->doSomething());
  }
}
?>

The test above assumes that testDoSomething() only works correctly whentestDoSomethingPrivate() works correctly. This means that we have indirectly testedtestDoSomethingPrivate(). The problem with this approach is that when the test fails we do not know directly where the root cause for the failure is. It could be in eithertestDoSomething() or testDoSomethingPrivate(). This makes the test less valuable.

PHPUnit supports reading protected and private attributes through thePHPUnit_Framework_Assert::readAttribute() method. Convenience wrappers such asPHPUnit_Framework_TestCase::assertAttributeEquals() exist to express assertions onprotected and private attributes:


<?php
class FooTest extends PHPUnit_Framework_TestCase
{
  public function testPrivateAttribute()
  {
    $this->assertAttributeEquals(
     'baz', /* expected value */
     'bar', /* attribute name */
     new Foo /* object     */
    );
  }
}
?>

PHP 5.3.2 introduces the ReflectionMethod::setAccessible() method to allow the invocation of protected and private methods through the Reflection API:


class testSample()
{
    $method = new ReflectionMethod('Sample', 'run');
    $method->setAccessible(true); // Will run Method is derived from the private Become similar to public Permissions of 
    $method->invoke(new Sample()); // Call run Method 
}

0

In the test above we directly test testDoSomethingPrivate(). When it fails we immediately know where to look for the root cause.

I agree with Dave Thomas and Andy Hunt, who write in their book "Pragmatic Unit Testing":

"In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out."

So: Just because the testing of protected and private attributes and methods is possible does not mean that this is a "good thing".

References:

http://php.net/manual/en/class.reflectionmethod.php

For more readers interested in PHP related content, please check the topics on this site: "Summary of PHP Error and Exception Handling Methods", "Summary of php String (string) Usage", "Encyclopedia of PHP Array (Array) Operation Skills", "Summary of PHP Operation and Operator Usage", "Summary of PHP Network Programming Skills", "Introduction to PHP Basic Syntax", "Introduction to php Object-Oriented Programming" and "Summary of php Excellent Development Framework"

I hope this article is helpful to everyone's PHP programming.


Related articles: