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中创建并处理图象
Oct 09 PHP
生成sessionid和随机密码的例子
Oct 09 PHP
PHP foreach循环使用详解与实例代码
May 08 PHP
8个出色的WordPress SEO插件收集
Feb 26 PHP
如何突破PHP程序员的技术瓶颈分析
Jul 17 PHP
二招解决php乱码问题
Mar 25 PHP
php include类文件超时问题处理
Feb 06 PHP
Laravel模板引擎Blade中section的一些标签的区别介绍
Feb 10 PHP
PHP安装memcached扩展笔记
May 28 PHP
PHP基于yii框架实现生成ICO图标
Nov 13 PHP
PHP上传Excel文件导入数据到MySQL数据库示例
Oct 25 PHP
PHP双向链表定义与用法示例
Jan 31 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
MOTOROLA 摩托罗拉 MODEL 66-XI五灯中波收音机
2021/03/02 无线电
两个开源的Php输出Excel文件类
2010/02/08 PHP
php中导出数据到excel时数字变为科学计数的解决方法
2013/02/03 PHP
PHP判断变量是否为0的方法
2014/02/08 PHP
PHP正则表达式函数preg_replace用法实例分析
2020/06/04 PHP
Javascript操纵Cookie实现购物车程序
2007/02/15 Javascript
js实现的网页颜色代码表全集
2007/07/17 Javascript
用JS实现一个页面多个css样式实现
2008/05/29 Javascript
js输出阴历、阳历、年份、月份、周示例代码
2014/01/29 Javascript
javascript获取元素偏移量的方法有哪些
2014/06/24 Javascript
javascript与css3动画结合使用小结
2015/03/11 Javascript
javascript实现标签切换代码示例
2016/05/22 Javascript
jquery获取input type=text中的值的各种方式(总结)
2016/12/02 Javascript
解决Jstree 选中父节点时被禁用的子节点也会选中的问题
2017/12/27 Javascript
vue之将echart封装为组件
2018/06/02 Javascript
泛谈JS逻辑判断选择器 || &amp;&amp;
2019/05/24 Javascript
vue实现瀑布流组件滑动加载更多
2020/03/10 Javascript
[01:09]2014DOTA2国际邀请赛 TI4西雅图DOTA2 中国美女coser加油助威
2014/07/20 DOTA
Python将xml和xsl转换为html的方法
2015/03/10 Python
Python双精度浮点数运算并分行显示操作示例
2017/07/21 Python
Python判断对象是否为文件对象(file object)的三种方法示例
2019/04/26 Python
django admin 添加自定义链接方式
2020/03/11 Python
Python openpyxl 插入折线图实例
2020/04/17 Python
scrapy处理python爬虫调度详解
2020/11/23 Python
Pandas中两个dataframe的交集和差集的示例代码
2020/12/13 Python
Python3自带工具2to3.py 转换 Python2.x 代码到Python3的操作
2021/03/03 Python
HTML+CSS+JavaScript实现图片3D展览的示例代码
2020/10/12 HTML / CSS
Urban Outfitters英国官网:美国平价服饰品牌
2016/11/25 全球购物
三陽商会官方网站:Sanyo iStore
2019/05/15 全球购物
客服实习的个人自我鉴定
2013/10/20 职场文书
挑战杯创业计划书的写作指南
2014/01/07 职场文书
高中军训感言500字
2014/02/24 职场文书
客户经理竞聘演讲稿
2014/05/15 职场文书
2015年员工试用期工作总结
2015/05/28 职场文书
python flask开发的简单基金查询工具
2021/06/02 Python
SpringBoot2零基础到精通之数据与页面响应
2022/03/22 Java/Android