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 错误之引号中使用变量
May 04 PHP
php学习之运算符相关概念
Jun 09 PHP
用Php编写注册后Email激活验证的实例代码
Mar 11 PHP
浅析51个PHP处理字符串的函数
Aug 02 PHP
一个PHP的远程图片抓取函数分享
Sep 25 PHP
php和jquery实现地图区域数据统计展示数据示例
Feb 12 PHP
php实现基于微信公众平台开发SDK(demo)扩展的方法
Dec 22 PHP
PHP数组函数array_multisort()用法实例分析
Apr 02 PHP
PHP单例模式是什么 php实现单例模式的方法
May 14 PHP
PHP实现字符串大小写转函数的功能实例
Feb 06 PHP
PHP结合jquery ajax实现上传多张图片,并限制图片大小操作示例
Mar 01 PHP
PHP使用HTML5 FormData对象提交表单操作示例
Jul 02 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/10/09 PHP
php编程实现获取excel文档内容的代码实例
2011/06/28 PHP
php计算数组不为空元素个数的方法
2014/01/27 PHP
PHP使用imagick读取PDF生成png缩略图的两种方法
2014/03/20 PHP
php实现批量压缩图片文件大小的脚本
2014/07/04 PHP
php实现统计目录文件大小的函数
2015/12/25 PHP
PHP聚合式迭代器接口IteratorAggregate用法分析
2017/12/28 PHP
Gambit vs CL BO3 第二场 2.13
2021/03/10 DOTA
prototype 1.5 &amp; scriptaculous 1.6.1 学习笔记
2006/09/07 Javascript
JS事件Event元素(兼容IE,Firefox,Chorme)
2012/11/01 Javascript
Javascript中For In语句用法实例
2015/05/14 Javascript
javascript去除空格方法小结
2015/05/21 Javascript
js实现的tab标签切换效果代码分享
2015/08/25 Javascript
js实现三张图(文)片一起切换的banner焦点图
2015/08/25 Javascript
javaScript语法总结
2016/11/25 Javascript
浅谈Node.js:Buffer模块
2016/12/05 Javascript
bootstrap3 dialog 更强大、更灵活的模态框
2017/04/20 Javascript
npm国内镜像 安装失败的几种解决方案
2017/06/04 Javascript
解决vue+webpack打包路径的问题
2018/03/06 Javascript
vue todo-list组件发布到npm上的方法
2018/04/04 Javascript
JavaScript实现构造json数组的方法分析
2018/08/17 Javascript
微信小程序开发(二):页面跳转并传参操作示例
2020/06/01 Javascript
[06:21]完美世界亚洲区首席发行官竺琦TI3采访
2013/08/26 DOTA
Python 自动安装 Rising 杀毒软件
2009/04/24 Python
让python同时兼容python2和python3的8个技巧分享
2014/07/11 Python
朴素贝叶斯分类算法原理与Python实现与使用方法案例
2018/06/26 Python
Python + selenium + crontab实现每日定时自动打卡功能
2020/03/31 Python
详解Python 函数参数的拆解
2020/09/02 Python
HTML5获取当前地理位置并在百度地图上展示的实例
2020/07/10 HTML / CSS
Hotels.com台湾:饭店订房网
2017/09/06 全球购物
TripAdvisor斯洛伐克:阅读评论、比较价格和酒店预订
2018/04/25 全球购物
三个Unix的命令面试题
2015/04/12 面试题
节能标语大全
2014/06/21 职场文书
学生偷窃检讨书
2014/09/25 职场文书
2014年标准化工作总结
2014/12/17 职场文书
Win10系统搭建ftp文件服务器详细教程
2022/08/05 Servers