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学习 字符串课件
Jun 15 PHP
php从数组中随机抽取一些元素的代码
Nov 05 PHP
PHP数据类型之整数类型、浮点数的介绍
Apr 28 PHP
Window下PHP三种运行方式图文详解
Jun 11 PHP
php缩放gif和png图透明背景变成黑色的解决方法
Oct 14 PHP
php生成html文件方法总结
Dec 01 PHP
PHP实现的一致性哈希算法完整实例
Nov 14 PHP
php实现统计目录文件大小的函数
Dec 25 PHP
Symfony生成二维码的方法
Feb 04 PHP
php5.2的curl-bug 服务器被php进程卡死问题排查
Sep 19 PHP
php生成微信红包数组的方法
Sep 05 PHP
php判断目录存在的简单方法
Sep 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
thinkphp微信开发(消息加密解密)
2015/12/02 PHP
Yii数据模型中rules类验证器用法分析
2016/07/15 PHP
JAVASCRIPT HashTable
2007/01/22 Javascript
永不消失的title提示代码
2007/02/15 Javascript
JavaScript等比例缩放图片控制超出范围的图片
2013/08/06 Javascript
Javascript验证用户输入URL地址是否为空及格式是否正确
2014/10/09 Javascript
jquery+CSS实现的多级竖向展开树形TRee菜单效果
2015/08/24 Javascript
vuex实现简易计数器
2016/10/27 Javascript
关于页面刷新vuex数据消失问题解决方案
2017/07/03 Javascript
在 Angular 中使用Chart.js 和 ng2-charts的示例代码
2017/08/17 Javascript
JavaScript代码实现txt文件的上传预览功能
2018/03/27 Javascript
jQuery实现的简单获取索引功能示例
2018/06/04 jQuery
JavaScript中发出HTTP请求最常用的方法
2018/07/12 Javascript
Vue 中对图片地址进行拼接的方法
2018/09/03 Javascript
nodejs微信开发之接入指南
2019/03/17 NodeJs
vue 源码解析之虚拟Dom-render
2019/08/26 Javascript
Postman参数化实现过程及原理解析
2020/08/13 Javascript
vue 项目软键盘回车触发搜索事件
2020/09/09 Javascript
Vue实现穿梭框效果
2020/09/30 Javascript
Python函数式编程指南(二):从函数开始
2015/06/24 Python
Django项目开发中cookies和session的常用操作分析
2018/07/03 Python
pycharm配置当鼠标悬停时快速提示方法参数
2019/07/31 Python
关于Python中的向量相加和numpy中的向量相加效率对比
2019/08/26 Python
python opencv 检测移动物体并截图保存实例
2020/03/10 Python
Python为何不支持switch语句原理详解
2020/10/21 Python
Python 删除List元素的三种方法remove、pop、del
2020/11/16 Python
java关于string最常出现的面试题整理
2021/01/18 Python
详解CSS3伸缩布局盒模型Flex布局
2018/08/20 HTML / CSS
俄罗斯儿童和青少年服装、鞋子及配件的在线商店:Orby
2020/02/20 全球购物
生物科学系大学生的自我评价
2013/12/20 职场文书
暑假社会实践证明格式
2014/10/28 职场文书
2014年检察院个人工作总结
2014/12/09 职场文书
高三复习计划
2015/01/19 职场文书
关于运动会的宣传稿
2015/07/23 职场文书
教师节随笔
2015/08/15 职场文书
python自动计算图像数据集的RGB均值
2021/06/18 Python