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 相关文章推荐
在字符串中把网址改成超级链接
Oct 09 PHP
PHP array操作10个小技巧分享
Jun 23 PHP
非常精妙的PHP递归调用与静态变量使用
Dec 16 PHP
PHP实现数字补零功能的2个函数介绍
May 12 PHP
用 Composer构建自己的 PHP 框架之设计 MVC
Oct 30 PHP
PHP+redis实现添加处理投票的方法
Nov 14 PHP
简单了解PHP编程中数组的指针的使用
Nov 30 PHP
PHP面向对象编程之深入理解方法重载与方法覆盖(多态)
Dec 24 PHP
php实现批量上传数据到数据库(.csv格式)的案例
Jun 18 PHP
php双层循环(九九乘法表)
Oct 23 PHP
PHP APP微信提现接口代码
Sep 30 PHP
详解PHP用mb_string处理windows中文字符
May 26 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
晋城吧对DiscuzX进行的前端优化要点
2010/09/05 PHP
smarty简单分页的实现方法
2014/10/27 PHP
php如何控制用户对图片的访问 PHP禁止图片盗链
2016/03/25 PHP
php删除二维数组中的重复值方法
2018/03/12 PHP
List the Codec Files on a Computer
2007/06/18 Javascript
详解强大的jQuery选择器之基本选择器、层次选择器
2012/02/07 Javascript
按Enter键触发事件的jquery方法实现代码
2014/02/17 Javascript
jquery向上向下取整适合分页查询
2014/09/06 Javascript
jquery比较简洁的软键盘特效实现方法
2015/03/19 Javascript
js实现简单的可切换选项卡效果
2015/04/10 Javascript
Markdown与Bootstrap相结合实现图片自适应属性
2016/05/04 Javascript
JQ选择器_选择同类元素的第N个子元素的实现方法
2016/09/08 Javascript
JavaScript奇技淫巧44招【实用】
2016/12/11 Javascript
js生成随机颜色方法代码分享(三种)
2016/12/29 Javascript
微信小程序 WebSocket详解及应用
2017/01/21 Javascript
JavaScript运动框架 解决防抖动问题、悬浮对联(二)
2017/05/17 Javascript
jQuery操作DOM_动力节点Java学院整理
2017/07/04 jQuery
BootStrap Fileinput插件和Bootstrap table表格插件相结合实现文件上传、预览、提交的导入Excel数据操作步骤
2017/08/07 Javascript
详解react-native-fs插件的使用以及遇到的坑
2017/09/12 Javascript
浅谈Node Inspector 代理实现
2017/10/19 Javascript
JavaScript实现精美个性导航栏筋斗云效果
2017/10/29 Javascript
Electron + vue 打包桌面操作流程详解
2019/06/24 Javascript
[07:01]DOTA2-DPC中国联赛正赛 Aster vs Magma 3月5日 赛后选手采访
2021/03/11 DOTA
Python设计模式之观察者模式简单示例
2018/01/10 Python
Python实现通过解析域名获取ip地址的方法分析
2019/05/17 Python
selenium 安装与chromedriver安装的方法步骤
2019/06/12 Python
python英语单词测试小程序代码实例
2019/09/09 Python
详解python破解zip文件密码的方法
2020/01/13 Python
Python读取文件内容为字符串的方法(多种方法详解)
2020/03/04 Python
HTML5之HTML元素扩展(下)—增强的Form表单元素值得关注
2013/01/31 HTML / CSS
鼠标滚轮事件和Mac触控板双指事件
2019/12/23 HTML / CSS
精神文明单位申报材料
2014/05/02 职场文书
党员目标管理责任书
2014/07/25 职场文书
淘宝文案策划岗位职责
2015/04/14 职场文书
python实现网络五子棋
2021/04/11 Python
MySQL和Oracle批量插入SQL的通用写法示例
2021/11/17 MySQL