本文實(shí)例講述了PHPUnit測(cè)試私有屬性和方法功能。分享給大家供大家參考,具體如下:
一、測(cè)試類(lèi)中的私有方法:
class Sample
{
private $a = 0;
private function run()
{
echo $a;
}
}
上面只是簡(jiǎn)單的寫(xiě)了一個(gè)類(lèi)包含,一個(gè)私有變量和一個(gè)私有方法。對(duì)于protected和private方法,由于無(wú)法像是用public方法一樣直接調(diào)用,所以在使用phpunit進(jìn)行單測(cè)的時(shí)候,多有不便,特別是當(dāng)一個(gè)類(lèi)中,對(duì)外只提供少量接口,內(nèi)部使用了大量private方法的情況。
對(duì)于protected方法,建議使用繼承的方式進(jìn)行測(cè)試,在此就不再贅述。而對(duì)于private方法的測(cè)試,建議使用php的反射機(jī)制來(lái)進(jìn)行。話(huà)不多說(shuō),上代碼:
class testSample()
{
$method = new ReflectionMethod('Sample', 'run');
$method->setAccessible(true); //將run方法從private變成類(lèi)似于public的權(quán)限
$method->invoke(new Sample()); //調(diào)用run方法
}
如果run方法是靜態(tài)的,如:
private static function run()
{
echo 'run is a private static function';
}
那么invoke函數(shù)還可以這么寫(xiě):
$method->invoke(null); //只有靜態(tài)方法可以不必傳類(lèi)的實(shí)例化
如果run還需要傳參,比如:
private function run($x, $y)
{
return $x + $y;
}
那么,測(cè)試代碼可以改為:
$method->invokeArgs(new Sample(), array(1, 2));
//array中依次寫(xiě)入要傳的參數(shù)。執(zhí)行結(jié)果返回3
【注意】:利用反射的方法測(cè)試私有方法雖好,但setAccessible函數(shù)是php5.3.2版本以后才支持的(>=5.3.2)
二、私有屬性的get/set
說(shuō)完了私有方法,再來(lái)看看私有屬性,依舊拿Sample類(lèi)作為例子,想要獲取或設(shè)置Sample類(lèi)中的私有屬性$a的值可以用如下方法:
public function testPrivateProperty()
{
$reflectedClass = new ReflectionClass('Sample');
$reflectedProperty = $reflectedClass->getProperty('a');
$reflectedProperty->setAccessible(true);
$reflectedProperty->getValue(); //獲取$a的值
$reflectedProperty->setValue(123); //給$a賦值:$a = 123;
}
上述方法對(duì)靜態(tài)屬性依然有效。
到此,是不是瞬間感覺(jué)測(cè)試私有方法或?qū)傩宰兊煤苋菀琢恕?/p>
附:PHPunit 測(cè)試私有方法(英文原文)
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".
參考文獻(xiàn):
http://php.net/manual/en/class.reflectionmethod.php
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《PHP錯(cuò)誤與異常處理方法總結(jié)》、《php字符串(string)用法總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《PHP網(wǎng)絡(luò)編程技巧總結(jié)》、《PHP基本語(yǔ)法入門(mén)教程》、《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》及《php優(yōu)秀開(kāi)發(fā)框架總結(jié)》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:- PHPUnit 單元測(cè)試安裝與使用入門(mén)教程
- ThinkPHP5與單元測(cè)試PHPUnit使用詳解
- PHPUnit + Laravel單元測(cè)試常用技能
- PHP使用phpunit進(jìn)行單元測(cè)試示例
- 使用PHPUnit進(jìn)行單元測(cè)試并生成代碼覆蓋率報(bào)告的方法
- php中PHPUnit框架實(shí)例用法