Тестування абстрактних занять


144

Як перевірити конкретні методи абстрактного класу за допомогою PHPUnit?

Я б очікував, що мені доведеться створити якийсь об’єкт у рамках тесту. Хоча я не знаю, що найкраща практика для цього чи якщо PHPUnit це дозволяє.


10
Можливо, варто подумати про зміну прийнятої відповіді.
Яків

1
Можливо, stackoverflow.com/a/2947823/23963 допоможе.
Найджел Торн

Відповіді:


240

Одиничне тестування абстрактних класів не означає тестування інтерфейсу, оскільки абстрактні класи можуть мати конкретні методи, і ці конкретні методи можна перевірити.

Не так вже й рідко, коли ви пишете якийсь код бібліотеки, мати певний базовий клас, який ви очікуєте розширити у вашому шарі програми. І якщо ви хочете переконатися, що код бібліотеки перевірений, вам потрібні засоби для UT конкретних методів абстрактних класів.

Особисто я використовую 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());
    }
}

Об'єкт макету дає вам декілька речей:

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

38

Це гарне запитання. Я теж це шукав.
На щастя, 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

Звучить цікаво, але ви б протестували проти макету? Якими будуть тести? IE: розширення макету в тестовому випадку та тестування на розширений тестовий клас?
stefgosselin

34

Слід зазначити, що станом на 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
}

4
Дякую за це! Використання анонімного класу в PHPUnit дало мені велику гнучкість у створенні моїх різних тестів.
Аліса Чудо

1

Еран, ваш метод повинен працювати, але це суперечить тенденції написання тесту до фактичного коду.

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

Ваші тести, очевидно, повинні перевірити визначені методи абстрактного класу, але завжди за допомогою підкласу.


Я вважаю довільною відповіддю: у вас є абстрактний клас 'A', який має загальний метод 'foo ()'. Цей метод 'foo ()' використовується загалом у всіх класах 'B' та 'C', обидва походять від 'A'. Який клас ви обрали б для тестування "foo ()"?
користувач3790897

1

Відповідь Нельсона неправильна.

Для абстрактних занять не потрібно, щоб усі їх методи були абстрактними.

Реалізовані методи - це те, що нам потрібно протестувати.

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

Ура.


0

Якщо ви не хочете підкласи абстрактного класу просто для того, щоб виконати одиничний тест методів, які вже реалізовані в абстрактному класі, ви можете спробувати перевірити, чи дозволяє ваша рамка глузувати з абстрактних класів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.