测试具有内部函数调用的函数

时间:2011-04-23 01:11:25

标签: php phpunit

我是一个单元测试初学者,似乎一直坚持如何对包含内部函数调用的函数进行单元测试。例如,测试以下内容:

public function getBlueFooCount($fooId) {
   $foo = $fooDao->getFoosById($fooId);

   // custom logic to pull out the blue foos from result set
   // custom count business logic on blue foos ...

   return $count;
}

我如何能够模拟内部函数检索的内容?这是因为函数耦合太紧,需要放松吗?

2 个答案:

答案 0 :(得分:2)

你需要模仿$fooDao。希望有一个setter或一个DI容器,你不是用new创建的(在这种情况下,它可能会紧密耦合。)

答案 1 :(得分:1)

为了构建@ aib的答案,当我们开始对遗留代码库进行单元测试时,我们的大多数类都是紧密耦合的,并且许多方法本身都在实例化新对象。虽然我们已经采取措施实施Dependency InjectionInversion of Control,但我们仍然遇到了数百个仍需要进行单元测试的课程。

在为遗留方法编写单元测试时,我们重构并将实例化拉出到一个新的小方法,然后我们可以存根。不是最好的模式,但它很便宜并且无需进行更大规模的重构即可完成工作。

class FooCounter {

    public function getFooDao(){
        return new FooDao();
    }

    public function getBlueFooCount($fooId) {
        /* was this
        $fooDao = new FooDao();
        */
        $foo = $this->getFooDao()->getFoosById($fooId);

        // custom logic to pull out the blue foos from result set
        // custom count business logic on blue foos ...

        return $count;
    }

}

class FooCounterTest extends PHPUnit_Framework_TestCase {

    public function test_getBlueFooCount(){
        $fooCounter = $this->getMock('FooCounter', array('getFooDao'));
        $fooCounter->expects($this->any())
                   ->method('getFooDao')
                   ->will($this->returnValue(new MockFooDao()));

        $this->assertEquals(0, $fooCounter->getBlueFooCount(1));
    }

}

如果我们正在实现一个新类,我们通常使用基于构造函数的DI,如果你要创建新的东西,我将给出答案。这是其他人的链接,因为我相信之前已经说过更好(有点干):Dependency Injection and Unit Testing。以及针对您的案例的每个例子:

基于构造函数的注入

class FooCounter {

    private $_fooDao

    public function __construct($fooDao){
        $this->_fooDao = $fooDao
    }

    public function getBlueFooCount($fooId) {
        $foo = $this->_fooDao->getFoosById($fooId);

        // custom logic to pull out the blue foos from result set
        // custom count business logic on blue foos ...

        return $count;
    }

}

class FooCounterTest extends PHPUnit_Framework_TestCase {

    public function test_getBlueFooCount(){
        $fooCounter = new FooCounter(new MockFooDao());

        $this->assertEquals(0, $fooCounter->getBlueFooCount(1));
    }

}

基于Setter的注射

class FooCounter {

    private $_fooDao

    public function setFooDao($fooDao){
        $this->_fooDao = $fooDao
    }

    public function getBlueFooCount($fooId) {
        $foo = $this->_fooDao->getFoosById($fooId);

        // custom logic to pull out the blue foos from result set
        // custom count business logic on blue foos ...

        return $count;
    }

}

class FooCounterTest extends PHPUnit_Framework_TestCase {

    public function test_getBlueFooCount(){
        $fooCounter = new FooCounter();
        $fooCounter->setFooDao(new MockFooDao());

        $this->assertEquals(0, $fooCounter->getBlueFooCount(1));
    }

}