我开始使用PHPUnit测试和模拟php中的方法。如果这些方法在同一类中,则没有问题。
但是我还不知道如何模拟另一个类中的方法。
class classA {
public function funcA() {
$classB = new classB();
$value = $classB->getValue();
return $value;
}
}
class classB {
public function getValue() {
return "this is my value";
}
}
如果getValue在classA中,则可以执行以下操作:
class testClassA {
function testFuncA() {
$mb = $this
->getMockBuilder(classA::class)
->setMethods(array('getValue'))
->getMock();
$mb
->method('getValue')
->will($this->returnValue('my new value');
$value = $mb->funcA();
$this->assertEquals('my new value', $value);
}
}
但是,在上面的情况下,我该怎么办呢?
修改:
Jon Stirling要求在构造函数中实例化classB而不是经过测试的方法
因此,让我们编辑classA
class classA {
$private classB;
public function __construct(){
$this->classB = new classB();
}
public function funcA() {
$value = $this->classB->getValue();
return $value
}
}
那怎么可能呢?
答案 0 :(得分:0)
代替实际分离类,以便测试可以在测试时注入classB
对象,答案是使用反射来替换类成员:
class classA {
private $classB;
public function __construct(){
$this->classB = new classB();
}
public function funcA() {
$value = $this->classB->getValue();
return $value
}
}
class testClassA {
function testFuncA() {
$mb = $this
->getMockBuilder(classB::class)
->setMethods(array('getValue'))
->getMock();
$mb
// XXX must be called EXACTLY once
->expects($this->once())
->method('getValue')
->will($this->returnValue('my new value');
$ma = $this
->getMockBuilder(classA::class)
->setMethods([
// XXX do not mock any methods except the constructor!
])
// XXX avoid any side effects from classA's constructor:
->disableOriginalConstructor()
->getMock();
// XXX inject the mock B into the mock A
$reflector = new ReflectionClass($ma);
$prop = $reflector->getProperty('classB');
$prop->setAccessible(true);
$prop->setValue($ma, $mb);
$value = $ma->funcA();
$this->assertEquals('my new value', $value);
}
}
->expects()
运算符视为断言。所有这些测试测试都是classA
对其getValue
成员调用$classB
方法。 IMO不太有用。