PHPUnit测试私有属性和方法功能示例


Posted in PHP onJune 12, 2018

本文实例讲述了PHPUnit测试私有属性和方法功能。分享给大家供大家参考,具体如下:

一、测试类中的私有方法:

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

上面只是简单的写了一个类包含,一个私有变量和一个私有方法。对于protected和private方法,由于无法像是用public方法一样直接调用,所以在使用phpunit进行单测的时候,多有不便,特别是当一个类中,对外只提供少量接口,内部使用了大量private方法的情况。

对于protected方法,建议使用继承的方式进行测试,在此就不再赘述。而对于private方法的测试,建议使用php的反射机制来进行。话不多说,上代码:

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

如果run方法是静态的,如:

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

那么invoke函数还可以这么写:

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

如果run还需要传参,比如:

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

那么,测试代码可以改为:

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

【注意】:利用反射的方法测试私有方法虽好,但setAccessible函数是php5.3.2版本以后才支持的(>=5.3.2)

二、私有属性的get/set

说完了私有方法,再来看看私有属性,依旧拿Sample类作为例子,想要获取或设置Sample类中的私有属性$a的值可以用如下方法:

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

上述方法对静态属性依然有效。

到此,是不是瞬间感觉测试私有方法或属性变得很容易了。

附:PHPunit 测试私有方法(英文原文)

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:

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
  /**
   * @covers Foo::doSomethingPrivate
   */
  public function testPrivateMethod()
  {
    $method = new ReflectionMethod(
     'Foo', 'doSomethingPrivate'
    );
    $method->setAccessible(TRUE);
    $this->assertEquals(
     'blah', $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".

参考文献:

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

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
mysql中存储过程、函数的一些问题
Feb 14 PHP
php获得当前的脚本网址
Dec 10 PHP
PHP文件读写操作之文件读取方法详解
Jan 13 PHP
PHP下通过file_get_contents的代理使用方法
Feb 16 PHP
用PHP写的基于Memcache的Queue实现代码
Nov 27 PHP
一个PHP的ZIP压缩类分享
May 04 PHP
php去掉URL网址中带有PHPSESSID的配置方法
Jul 08 PHP
thinkphp四种url访问方式详解
Nov 28 PHP
php实现粘贴截图并完成上传功能
May 17 PHP
Linux安装配置php环境的方法
Jan 14 PHP
Laravel使用PHPQRCODE实现生成带有LOGO的二维码图片功能示例
Jul 07 PHP
Laravel框架搜索分页功能示例
Feb 01 PHP
PHP+redis实现的悲观锁机制示例
Jun 12 #PHP
thinkPHP5框架auth权限控制类与用法示例
Jun 12 #PHP
thinkPHP5框架实现基于ajax的分页功能示例
Jun 12 #PHP
Laravel框架路由和控制器的绑定操作方法
Jun 12 #PHP
Laravel框架路由设置与使用示例
Jun 12 #PHP
Laravel框架生命周期与原理分析
Jun 12 #PHP
Laravel框架分页实现方法分析
Jun 12 #PHP
You might like
PHP的中问验证码
2006/11/25 PHP
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
2009/01/30 PHP
php中sprintf与printf函数用法区别解析
2014/02/17 PHP
PHP启动windows应用程序、执行bat批处理、执行cmd命令的方法(exec、system函数详解)
2014/10/20 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
脚本吧 - 幻宇工作室用到js,超强推荐expand.js
2006/12/23 Javascript
Javascript 判断函数类型完美解决方案
2009/09/02 Javascript
firefox和IE系列的相关区别整理 以备后用
2009/12/28 Javascript
全面解析多种Bootstrap图片轮播效果
2016/05/27 Javascript
什么是JavaScript中的结果值?
2016/10/08 Javascript
Javascript 函数的四种调用模式
2016/11/05 Javascript
js实现九宫格的随机颜色跳转
2017/02/19 Javascript
angularjs实现上拉加载和下拉刷新数据功能
2017/06/12 Javascript
angularjs 的数据绑定实现原理
2018/07/02 Javascript
详解React中合并单元格的正确写法
2019/01/08 Javascript
微信小程序中使用Async-await方法异步请求变为同步请求方法
2019/03/28 Javascript
vue配置nprogress实现页面顶部进度条
2019/09/21 Javascript
微信小程序(订阅消息)功能
2019/10/25 Javascript
[26:21]浴火之凤-TI4世界冠军Newbee战队纪录片
2014/08/07 DOTA
Python中生成器和yield语句的用法详解
2015/04/17 Python
Python解惑之True和False详解
2017/04/24 Python
python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别
2018/06/04 Python
Django基础知识与基本应用入门教程
2018/07/20 Python
python实现图片识别汽车功能
2018/11/30 Python
Python3远程监控程序的实现方法
2019/07/15 Python
双向RNN:bidirectional_dynamic_rnn()函数的使用详解
2020/01/20 Python
MoviePy简介及Python视频剪辑自动化
2020/12/18 Python
火山动力Java笔试题
2014/06/26 面试题
化工工艺专业求职信
2013/09/22 职场文书
中班中秋节活动反思
2014/02/18 职场文书
健康教育评估方案
2014/05/25 职场文书
英语专业自荐书
2014/06/13 职场文书
2014年车间工作总结
2014/11/21 职场文书
新生开学寄语大全
2015/05/28 职场文书
小学生家长意见
2015/06/03 职场文书
旗帜观后感
2015/06/08 职场文书