Подтвердить что ты не робот

PHPUnit - Написание тестового класса для интерфейса и тестирование объектов с помощью factory

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

Мой план состоял в том, чтобы написать тестовый класс, который будет принимать объект factory для конструктора (инъекция зависимостей) и использовать factory для создания новых экземпляров тестируемого класса.

Таким образом, если бы я хотел протестировать ClassA, я мог бы передать объект ClassAFactory конструктору тестового класса, и если бы я захотел проверить ClassB, я бы передал объект ClassBFactory. Оба класса предназначены для взаимозаменяемости, и поскольку предполагается, что тестируются только публичные методы, это кажется идеальным.

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

Если бы я использовал первую идею, я бы предположил, что у меня будет тестовый класс для каждого тестируемого класса, например:

class ClassATest extends [PHPUnit test case]
{
    $myFactory = new ClassAFactory();
    $myTest = new ClassTest($myFactory);

    $myTest->test1();
    $myTest->test2();
    //etc.
}

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

4b9b3361

Ответ 1

Думаю, вам нужно пересмотреть свой план. Вы не можете протестировать интерфейс и есть веская причина - интерфейсы просто определяют API, а не функциональность, тестируют функциональность тестирования. Позвольте мне привести вам пример, который может помочь. Скажем, у вас есть интерфейс обмена сообщениями. Таким образом, вы реализуете EmailMessager и SMSMessager. Теперь вам нужно протестировать их отдельно, как с помощью EmailMessager, вам нужно убедиться, что он делает все возможное, может быть, проверка адресата (адрес электронной почты) и, возможно, делегирование отправки в класс электронной почты и т.д. Очевидно, что SMS-сообщение будет отличаться.

Ответ 2

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

abstract class IAdderTestCase extends PFTC
{
    function testAdd() {
        self::assertEquals(5, $this->fixture->add(2, 3));
    }
    ...
}

class BasicAdderTest extends IAdderTestCase
{
    function setUp() {
        $this->fixture = new BasicAdder();
    }
}

PHPUnit будет вызывать setUp() перед каждым методом тестирования. Он должен вызывать все унаследованные методы тестирования для каждого конкретного подкласса плюс любые дополнительные, например. для проверки конструкторов.