Тестирование функции с внутренним вызовом функции - PullRequest
2 голосов
/ 23 апреля 2011

Я начинающий юнит-тестирование и, похоже, застрял в том, как юнит-тестирование функции, содержащей внутренний вызов функции. Например, тестирование следующее:

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 ]

2 голосов
/ 23 апреля 2011

Надо издеваться $fooDao. Надеюсь, есть сеттер или DI-контейнер, и вы не создаете его с помощью new (в этом случае он может быть слишком тесно связан).

1 голос
/ 26 апреля 2011

Чтобы построить ответ @ aib, когда мы начали модульное тестирование нашей унаследованной кодовой базы, большинство наших классов были очень тесно связаны, и многие методы сами создавали новые объекты. Хотя мы предприняли шаги по внедрению Dependency Injection и Inversion 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 на основе конструктора, и я дам ответ, если вы создаете что-то новое. Вот ссылка, сделанная кем-то другим, потому что я уверен, что раньше было сказано лучше (вроде DRY): Внедрение зависимостей и модульное тестирование . И несколько примеров каждого для вашего случая:

Инжектор на основе конструктора

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));
    }

}

Сеттер впрыска

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));
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...