如何在PHPUnit中存根一个由test的构造函数中的类调用的方法?例如,下面的简单代码将无法工作,因为在我声明存根方法时,已经创建了存根对象,并且我的方法被调用,取消存储.
要测试的类:
class ClassA {
private $dog;
private $formatted;
public function __construct($param1) {
$this->dog = $param1;
$this->getResultFromRemoteServer();
}
// Would normally be private, made public for stubbing
public getResultFromRemoteServer() {
$this->formatted = file_get_contents('http://whatever.com/index.php?'.$this->dog);
}
public getFormatted() {
return ("The dog is a ".$this->formatted);
}
}
Run Code Online (Sandbox Code Playgroud)
测试代码:
class ClassATest extends PHPUnit_Framework_TestCase {
public function testPoodle() {
$stub = $this->getMockBuilder('ClassA')
->setMethods(array('getResultFromRemoteServer'))
->setConstructorArgs(array('dog52'))
->getMock();
$stub->expects($this->any())
->method('getResultFromRemoteServer')
->will($this->returnValue('Poodle'));
$expected = 'This dog is a Poodle';
$actual = $stub->getFormatted();
$this->assertEquals($expected, $actual);
}
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*ess 48
使用,disableOriginalConstructor()以便getMock()不会调用构造函数.这个名字是有点误导,因为调用该方法,最终传递false的$callOriginalConstructor.这允许您在手动调用构造函数之前设置对返回的mock的期望.
$stub = $this->getMockBuilder('ClassA')
->setMethods(array('getResultFromRemoteServer'))
->disableOriginalConstructor()
->getMock();
$stub->expects($this->any())
->method('getResultFromRemoteServer')
->will($this->returnValue('Poodle'));
$stub->__construct('dog52');
...
Run Code Online (Sandbox Code Playgroud)
Gor*_*don 14
问题不在于方法的存在,而在于你的课程.
你正在构造函数中工作.要将对象设置为状态,请获取远程文件.但该步骤不是必需的,因为该对象不需要该数据处于有效状态.在实际调用之前,您不需要文件中的结果getFormatted.
你可以推迟加载:
class ClassA {
private $dog;
private $formatted;
public function __construct($param1) {
$this->dog = $param1;
}
protected getResultFromRemoteServer() {
if (!$this->formatted) {
$this->formatted = file_get_contents(
'http://whatever.com/index.php?' . $this->dog
);
}
return $this->formatted;
}
public getFormatted() {
return ("The dog is a " . $this->getResultFromRemoteServer());
}
}
Run Code Online (Sandbox Code Playgroud)
所以你懒得加载远程访问它实际需要的时候.现在你getResultFromRemoteServer根本不需要存根,但可以存根getFormatted.您也不需要打开API进行测试并getResultFromRemoteServer公开.
在旁注中,即使它只是一个例子,我也会重写那个类来阅读
class DogFinder
{
protected $lookupUri;
protected $cache = array();
public function __construct($lookupUri)
{
$this->lookupUri = $lookupUri;
}
protected function findById($dog)
{
if (!isset($this->cache[$dog])) {
$this->cache[$dog] = file_get_contents(
urlencode($this->lookupUri . $dog)
);
}
return $this->cache[$id];
}
public function getFormatted($dog, $format = 'This is a %s')
{
return sprintf($format, $this->findById($dog));
}
}
Run Code Online (Sandbox Code Playgroud)
由于它是一个Finder,findById现在实际公开可能更有意义.只是保护它,因为这就是你的例子.
另一种选择是扩展测试对象并getResultFromRemoteServer用您自己的实现返回替换该方法Poodle.这意味着你不是在测试实际的ClassA,而是测试它的子类ClassA,但这就是当你使用Mock API时会发生的事情.
从PHP7开始,您可以使用这样的Anonymous类:
public function testPoodle() {
$stub = new class('dog52') extends ClassA {
public function getResultFromRemoteServer() {
return 'Poodle';
}
};
$expected = 'This dog is a Poodle';
$actual = $stub->getFormatted();
$this->assertEquals($expected, $actual);
}
Run Code Online (Sandbox Code Playgroud)
在PHP7之前,您只需编写一个扩展测试对象的常规类,并使用它而不是测试对象.或使用disableOriginalConstructor本页其他地方所示.
| 归档时间: |
|
| 查看次数: |
10068 次 |
| 最近记录: |