2009-07-22 25 views
20

我试图从SimpleTest迁移到PHPUnit一堆测试,我想知道是否有一个等效的SimpleTest的partial mocksPHPUnit中的SimpleTest“partial mocks”的等价物?

更新:我似乎无法找到任何暗示该功能可用的文档,但它发生在我身上,我可以只使用一个子类。这是个好主意还是坏主意?

class StuffDoer { 
    protected function doesLongRunningThing() { 
     sleep(10); 
     return "stuff"; 
    } 
    public function doStuff() { 
     return $this->doesLongRunningThing(); 
    } 
} 
class StuffDoerTest { 
    protected function doesLongRunningThing() { 
     return "test stuff"; 
    } 
} 
class StuffDoerTestCase extends PHPUnit_Framework_TestCase { 
    public function testStuffDoer() { 
     $sd = new StuffDoerTest(); 
     $result = $sd->doStuff(); 
     $this->assertEquals($result, "test stuff"); 
    } 
} 
+0

感谢子类的想法! – Kyslik 2017-03-25 20:11:23

回答

40

从阅读链接页面,SimpleTest部分模拟似乎是一个模拟,只有一些方法被覆盖。如果这是正确的,则该功能由正常的PHPUnit模拟处理。

里面一个PHPUnit_Framework_TestCase,您创建一个模拟与

$mock = $this->getMock('Class_To_Mock'); 

它创建一个模拟实例,其中所有的方法什么也不做,返回null。如果您只想覆盖某些方法,则getMock的第二个参数是一组要覆盖的方法。

$mock = $this->getMock('Class_To_Mock', array('insert', 'update')); 

将创建一个Class_To_Mock模拟实例与insertupdate功能去掉,准备要指定自己的返回值。

此信息是在phpunit docs

注意this answer显示更多最新的代码示例,启动5.4

1

我不认为PHPUnit的支持被测系统部分嘲笑PHPUnit的版本。如果你试图隔离方法,那么我确定你的实现工作 - 我也这样做了。

但是,我尝试避免这样做,原因有两个。

首先,它将您的测试非常紧密地与班级的内部实施相结合。你真的关心一个名为doesLongRunningThing的方法是否被调用,还是“LongRunningThing”完成更重要?

其次,当我遇到这个问题时,总是让我怀疑我是否有一个班级做两个人的工作。一个提取类重构可能是为了。即使使用单一方法,如果doesLongRunningThing()成为其自己的类别,测试变得更加容易。

我相信解决方案是注入您的SUT依赖的服务(http://en.wikipedia.org/wiki/Dependency_injection)。这也使得DoesLongRunningThing实现更具可测性。

没有跳进接口,这里就是我会做:

class DoesLongRunningThing { 
    public function execute() { 
     sleep(10); 
     return "stuff"; 
    } 
} 

class StuffDoer { 
    protected $doesLongRunningThing; 

    public function setLongRunningThinger(DoesLongRunningThing $obj) { 
     $this->doesLongRunningThing = $obj; 
    } 

    public function doStuff() { 
     return $this->doesLongRunningThing->execute(); 
    } 
} 

现在可以很容易地模拟:

class StuffDoerTestCase extends PHPUnit_Framework_TestCase { 
    public function testStuffDoer() { 
     $dlrtMock = $this->getMock('DoesLongRunningThing'); 
     $dlrtMock->expects($this->any())->will($this->returnValue("test stuff")); 

     $sd = new StuffDoer(); 
     $sd->setLongRunningThinger($dlrtMock); 
     $result = $sd->doStuff(); 
     $this->assertEquals($result, "test stuff"); 
    } 
} 
+0

我认为PHPUnit只是一个工具,它并不关心被测系统(这是一个工具用户的交易)。根据Brenton的回答,PHPUnit _supports_“部分嘲讽”。从第一句话开始,你的答案是完美的(+1)。 – 2015-07-13 06:25:44

8

PHPUnit_Framework_TestCase::getMock is deprecated since phpunit 5.4。我们可以用setMethods代替。

setMethods(array $ methods)可以在Mock Builder对象上调用,以指定要用可配置测试double替换的方法。其他方法的行为不会改变。如果您调用setMethods(null),则不会替换任何方法。

https://phpunit.de/manual/current/en/test-doubles.html

$observer = $this->getMockBuilder(Observer::class) 
       ->setMethods(['update']) 
       ->getMock(); 

注意上面getMockPHPUnit_Framework_MockObject_MockBuilder::getMock。 (phpunit5.6)