Тестирование Абстрактных Классов


Как проверить конкретные методы абстрактного класса с помощью PHPUnit?

Я ожидал бы, что мне придется создать какой-то объект в рамках теста. Хотя, я понятия не имею, лучшая практика для этого или если PHPUnit позволяет это.

6 122

6 ответов:

модульное тестирование абстрактных классов не обязательно означает тестирование интерфейса, так как абстрактные классы могут иметь конкретные методы, и эти конкретные методы могут быть протестированы.

это не так уж редко, при написании некоторого кода библиотеки, чтобы иметь определенный базовый класс, который вы ожидаете расширить в вашем прикладном уровне. И если вы хотите убедиться, что код библиотеки проверен, вам нужны средства для использования конкретных методов абстрактных классов.

лично я использую PHPUnit, и это так называемые заглушки и макеты объектов, чтобы помочь вам испытать такого рода вещи.

прям от PHPUnit руководство:

abstract class AbstractClass
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($stub->concreteMethod());
    }
}

макет объекта дает вам несколько вещей:

  • вы не обязаны иметь конкретную реализацию абстрактного класса, и может уйти с заглушкой вместо
  • вы можете вызвать конкретные методы и утверждать, что они работают правильно
  • если конкретный метод полагается к unimplemented (абстрактный) метод, вы можете заглушить возвращаемое значение с помощью метода will() PHPUnit

Это хороший вопрос. Я тоже это искал.
К счастью, PHPUnit уже имеет getMockForAbstractClass() метод для этого случая, например,

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

важно:

обратите внимание, что для этого требуется PHPUnit > 3.5.4. Там было ошибка в предыдущих версиях.

для обновления до последней версии:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit

следует отметить, что начиная с PHP 7 поддержка анонимные классы была добавлена. Это дает вам дополнительный путь для настройки теста для абстрактного класса, который не зависит от функциональности PHPUnit-specific.

class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var AbstractClass
     */
    private $testedClass;

    public function setUp()
    {
        $this->testedClass = new class extends AbstractClass {

            protected function abstractMethod()
            {
                // Put a barebones implementation here
            }
        };
    }

    // Put your tests here
}

Eran, ваш метод должен работать, но это идет вразрез с тенденцией написания теста перед фактическим кодом.

Я бы предложил написать ваши тесты на желаемую функциональность неабстрактного подкласса рассматриваемого абстрактного класса, затем написать как абстрактный класс, так и реализующий подкласс и, наконец, запустить тест.

ваши тесты должны, очевидно, проверить определенные методы абстрактного класса, но всегда через подкласс.

Нельсона-это неправильно.

абстрактные классы не требуют, чтобы все их методы были абстрактными.

реализованные методы, которые нам нужно проверить.

Что вы можете сделать, это создать поддельный класс заглушки в файле модульного теста, расширить абстрактный класс и реализовать только то, что требуется без каких-либо функций вообще, конечно, и проверить это.

Ура.

Если вы не хотите подкласс абстрактного класса только для выполнения модульного теста на методы, которые уже реализованы в абстрактном классе, вы можете попробовать посмотреть, позволяет ли ваша структура mock абстрактные классы.