如果调用方法,则进行单元测试的最佳实践

时间:2014-08-16 11:45:52

标签: unit-testing phpunit

想象一下,我们有一个简单的控制器,其中包含用于注册服务的方法。它只应在不退出时插入DB / File系统。 (我知道在SQL中这是可能的)

<?php
class ServiceController {

    protected $c;

    public function __construct($c){
        $this->c = $c;
    }

    public function register($name, $protocol, $type){
        $serviceMapper = $this->c['SerivceMapper'];
        $service =  new Service(); // entity
        $service->setName($name);
        $service->setProtocol($protocol);
        $service->setType($type);
        if (!$serviceMapper->exists($service)){
            $serviceMapper->insert($service);
    }
}

现在我要测试这个控制器。特别是如果在servicemapper上调用insert方法。 有2个测试用例:服务已经退出时以及何时不存在。 我找到了一种测试方法,但看起来这是一种不好的做法,并且有一种更好的方法。

class ServiceControllerTest extends PHPUnit_Framework_TestCase {

    public function testRegisterWhenItExists(){
        $c = new Container();
        $c['ServiceMapper'] = $this->getMockBuilder('ServicedMapper')
            ->disableOriginalConstructor()
            ->getMock();


        $c['ServiceMapper']->expects($this->any())
           ->method('exists')
            ->will($this->returnValue(false));


        $c['BackendMapper']->expects($this->any())
            ->method('insert')
            ->will($this->returnCallback(function($entity){
                ServiceControllTest::insertExec = true;
        }));

        $serviceController = new ServiceController($c);
        $serviceController->register('foo', 'bar', 'foobar');

        $this->assertEquals(true, self::insertExec);

    }

    public function testRegisterWhenItDoesntExists(){
        // Almost the same as in the other test
    }
}

这是测试此方法的正确方法吗?有没有更好的方法?谢谢:))

编辑:我想我找到了正确的方法:

 public function testRegisterWhenItExists(){
        $c = new Container();
        $c['ServiceMapper'] = $this->getMockBuilder('ServicedMapper')
            ->disableOriginalConstructor()
            ->getMock();

        $service = new Service();
        $service->setName('foo');
        $service->setProtocol('bar');
        $service->setType('foobar');


        $c['ServiceMapper']->expects($this->any())
           ->method('exists')
           ->with($this->equalTo($service)) 
            ->will($this->returnValue(false));


        $c['BackendMapper']->expects($this->any())
            ->method('insert')
           ->with($this->equalTo($service));


        $serviceController = new ServiceController($c);
        $serviceController->register('foo', 'bar', 'foobar');


}

这是测试它的正确方法吗?

1 个答案:

答案 0 :(得分:0)

我几乎可以肯定我找到了确保在模拟上调用函数的正确方法。

// This will assert that the "exists" function can be called 0,1 or more times    
$c['ServiceMapper']->expects($this->any())
    ->method('exists')
    ->with($this->equalTo($service)) 
    ->will($this->returnValue(false));


// This will assert that the "exists" function can be called 0 times    
// when the "exists" method is called, the unit test will fail
$c['ServiceMapper']->expects($this->never())
    ->method('exists')
    ->with($this->equalTo($service)) 
    ->will($this->returnValue(false));

完整文档位于http://phpunit.de/manual/3.7/en/test-doubles.html#test-doubles.mock-objects.tables.matchers