我正在编写一个
PHPUnit测试,我需要模拟一些依赖项,但我需要一些方法,它仍然像以前一样工作.即,我有:
class Dependency { // some stuff not important for the test public function thisOneINeed() { /// complex code } // some more stuff }
所以我做了这样的事情:
// prepare mock object $dep = $this->getMockBuilder('Dependency')->disableOriginalConstructor()->getMock(); // mock out some other method that should return fixed value $dep->expects($this->any())->method("shouldGetTrue")->will($this->returnValue(true)); // run test code,it will use thisOneINeed() and shouldGetTrue() $result = $testSubject->runSomeCode($dep); $this->assertEquals($expected,$result);
一切都很好,除了方法thisOneINeed()被模拟出来,所以我没有得到复杂的代码来运行,我需要它运行runSomeCode()才能正常工作. thisOneINeed()中的代码不会调用任何其他方法,但它需要正确的测试,并且它不会返回固定值,所以我不能只将静态returnValue()放在那里.并且AFAIK PHPunit没有像returnValue()这样的方法来说“call parent”.它有returnCallback(),但就我所见,没有办法告诉它“为父类调用这个方法”.
我可以在Dependency中创建所有方法的列表,从中删除thisOneINeed并在构造模拟时将其传递给setMethods(),但我不喜欢这种方法,看起来像kludgy.
我也可以这样做:
class MockDependency extends Dependency { // do not let the mock kill thisOneINeed function final public function thisOneINeed() { return parent::thisOneINeed(); } }
然后使用MockDependency来构建模拟对象,这也有效,但我不喜欢手动进行模拟.
那么有更好的方法吗?
我想如果你想使用PHPUnit的模拟构建器,那么创建所有方法的数组,删除你需要的那个,并将它传递给setMethods正是你需要做的.
我个人发现在很多情况下有一个ReflectionClass的子类,我可以在需要时添加方法.
class MyReflectionClass extends ReflectionClass { public function getAllMethodNamesExcept(array $excluded) { $methods = array_diff( get_class_methods($this->name),$excluded ); return $methods; } }
您还可以使用支持您想要执行的操作的其他模拟框架.例如,Phake具有thenCallParent方法.我最近开始使用Phake因为我需要能够捕获传递给方法的参数.这是有据可查的,值得一试.