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 相关文章推荐
php时区转换转换函数
Jan 07 PHP
PHP URL参数获取方式的四种例子
Feb 28 PHP
php获取文件夹路径内的图片以及分页显示示例
Mar 11 PHP
解决CodeIgniter伪静态失效
Jun 09 PHP
浅析PHP中strlen和mb_strlen的区别
Aug 31 PHP
php实现根据字符串生成对应数组的方法
Sep 22 PHP
PHP中is_dir()函数使用指南
May 08 PHP
详解PHP的Yii框架中组件行为的属性注入和方法注入
Mar 18 PHP
PHPExcel中文帮助手册|PHPExcel使用方法(分享)
Jun 09 PHP
PHP Redis扩展无法加载的问题解决方法
Aug 22 PHP
laravel5.1框架model类查询的实现方法
Oct 08 PHP
PHP网站常见安全漏洞,及相应防范措施总结
Mar 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 UTF8中文字符截断函数代码
2012/09/11 PHP
解析PHP生成静态html文件的三种方法
2013/06/18 PHP
ubuntu下配置nginx+php+mysql详解
2015/09/10 PHP
php等比例缩放图片及剪切图片代码分享
2016/02/13 PHP
php获取远程图片并下载保存到本地的方法分析
2016/10/08 PHP
js关闭父窗口时关闭子窗口
2013/04/01 Javascript
js截取中英文字符串、标点符号无乱码示例解读
2014/04/17 Javascript
js处理php输出时间戳对不上号的解决方法
2014/06/20 Javascript
Javascript学习笔记之 函数篇(三) : 闭包和引用
2014/11/23 Javascript
JS烟花背景效果实现方法
2015/03/03 Javascript
JavaScript中的this关键字使用方法总结
2015/03/13 Javascript
JS与HTML结合使用marquee标签实现无缝滚动效果代码
2016/07/05 Javascript
js实现固定宽高滑动轮播图效果
2017/01/13 Javascript
想用好React的你必须要知道的一些事情
2017/07/24 Javascript
深入理解Vue.js源码之事件机制
2017/09/27 Javascript
vue中$nextTick的用法讲解
2019/01/17 Javascript
js实现直播点击飘心效果
2020/08/19 Javascript
[01:04:48]VGJ.S vs TNC Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
[02:19]2018年度DOTA2最佳核心位选手-完美盛典
2018/12/17 DOTA
[08:38]DOTA2-DPC中国联赛 正赛 VG vs Elephant 选手采访
2021/03/11 DOTA
使用Python中的greenlet包实现并发编程的入门教程
2015/04/16 Python
Python中模块string.py详解
2017/03/12 Python
单链表反转python实现代码示例
2018/02/08 Python
python实现傅里叶级数展开的实现
2018/07/21 Python
Python爬虫实现的根据分类爬取豆瓣电影信息功能示例
2019/09/15 Python
Pycharm自动添加文件头注释和函数注释参数的方法
2020/10/23 Python
使用HTML5的File实现base64和图片的互转
2013/08/01 HTML / CSS
莫斯科隐形眼镜网上商店:Linzi
2019/07/22 全球购物
初三物理教学反思
2014/01/21 职场文书
抽样调查项目计划书
2014/04/24 职场文书
个人担保书格式范文
2014/05/12 职场文书
计划生育个人总结
2015/03/02 职场文书
2015年初中生自我评价范文
2015/03/03 职场文书
阿凡达观后感
2015/06/10 职场文书
《清澈的湖水》教学反思
2016/02/17 职场文书
Java 多线程并发FutureTask
2022/06/28 Java/Android