Home  >  Article  >  Backend Development  >  Functional analysis of private properties and methods for PHPUnit testing

Functional analysis of private properties and methods for PHPUnit testing

不言
不言Original
2018-06-12 16:43:421363browse

This article mainly introduces the functions of PHPUnit for testing private properties and methods. It also analyzes in detail the relevant operating techniques and precautions for using PHPUnit to test private properties and methods in the form of examples. Friends in need can refer to the following

The examples in this article describe PHPUnit testing private properties and method functions. Share it with everyone for your reference, the details are as follows:

1. Private methods in the test class:

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

The above simply writes a class containing, a private variable and a private method. For protected and private methods, since they cannot be called directly like public methods, it is very inconvenient when using phpunit for single testing, especially when a class only provides a small number of interfaces to the outside world and uses a large number of private methods internally. Case.

For protected methods, it is recommended to use inheritance for testing, so I won’t go into details here. For testing private methods, it is recommended to use PHP's reflection mechanism. Without further ado, here’s the code:

class testSample()
{
    $method = new ReflectionMethod('Sample', 'run');
    $method->setAccessible(true); //将run方法从private变成类似于public的权限
    $method->invoke(new Sample()); //调用run方法
}

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 like this:

$method->invoke(null); //只有静态方法可以不必传类的实例化

If run still needs to pass parameters, for example:

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

Then, the test code can be changed to:

$method->invokeArgs(new Sample(), array(1, 2));
//array中依次写入要传的参数。执行结果返回3

[Note]: Use reflection to test private Although the method is good, the setAccessible function is only supported after php5.3.2 (>=5.3.2)

2. Get/set of private attributes

After talking about private methods, let’s take a look at private properties. Still taking the Sample class as an example, if you want to get or set the value of the private property $a in the Sample class, you can use the following method:

public function testPrivateProperty()
{
  $reflectedClass = new ReflectionClass('Sample');
  $reflectedProperty = $reflectedClass->getProperty('a');
  $reflectedProperty->setAccessible(true);
  $reflectedProperty->getValue(); //获取$a的值
  $reflectedProperty->setValue(123); //给$a赋值:$a = 123;
}

The above method is still valid for static properties.

At this point, it seems that testing private methods or properties has become easy instantly.

Attachment: PHPunit testing private methods (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 = &#39;baz&#39;;
  public function doSomething()
  {
    return $this->bar = $this->doSomethingPrivate();
  }
  private function doSomethingPrivate()
  {
    return &#39;blah&#39;;
  }
}
?>

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(&#39;blah&#39;, $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 either testDoSomething() or testDoSomethingPrivate(). This makes the test less valuable.

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

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
  public function testPrivateAttribute()
  {
    $this->assertAttributeEquals(
     &#39;baz&#39;, /* expected value */
     &#39;bar&#39;, /* 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:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
  /**
   * @covers Foo::doSomethingPrivate
   */
  public function testPrivateMethod()
  {
    $method = new ReflectionMethod(
     &#39;Foo&#39;, &#39;doSomethingPrivate&#39;
    );
    $method->setAccessible(TRUE);
    $this->assertEquals(
     &#39;blah&#39;, $method->invoke(new Foo)
    );
  }
}
?>

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

The above is the entire content of this article. I hope it will be helpful to everyone's study. For more related content, please pay attention to the PHP Chinese website!

related suggestion:

Analysis of pessimistic locking mechanism implemented by PHP and redis

Summary of the use of variable functions in PHP

The above is the detailed content of Functional analysis of private properties and methods for PHPUnit testing. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn