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

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

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

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.

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
}

Эран, ваш метод должен работать, но он идет против тенденции написания тестов до кода.

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

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


ответ Нельсона неверен.

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

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

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

Ура.


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