Как реализовать функциональность TDD в базовом классе mixin из одного из листовых классов? - PullRequest
1 голос
/ 27 августа 2009

после этого вопроса (Разработка интерфейса с TDD), у меня все еще есть некоторые проблемы.

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

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

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

Это проблема с моим дизайном? Должен ли я выложить свои тесты по-другому? Или я ни о чем не беспокоюсь?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 27 августа 2009

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

Предположим, у вас есть абстрактный класс с именем MyBase. Очевидно, что вы не можете создать экземпляр MyBase напрямую, но в вашем проекте модульного тестирования вы можете создать специализацию MyBase для конкретного теста под названием TestableBase или что-то еще.

Итак, давайте предположим, что вы хотите проверить что-то вроде этого:

public class MyBase
{
    public abstract void DoStuffCore();

    public void DoStuff()
    {
        // Do something interesting first
        this.DoStuffCore();
    }
}

И вы хотите проверить, что DoStuffCore был правильно вызван DoStuff, вы можете создать что-то вроде этого:

public class Spy : MyBase
{
    public bool CoreInvoked { get; private set; }

    public override void DoStuffCore()
    {
        this.CoreInvoked = true;
    }
}

Это позволит вам создать новый экземпляр Spy и вызвать его метод DoStuff, а затем впоследствии убедиться, что свойство CoreInvoked имеет значение true.

0 голосов
/ 27 августа 2009

Один из подходов, который вы можете использовать, - это организовать тестовые блоки, чтобы вы могли повторно использовать тестовый код. Таким образом, вам не нужно копировать / вставлять вещи (копирование / вставка, даже если это для тестов, обычно не то, что вы хотите делать).

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

Однако такого рода вещи случаются редко. Обычно при рефакторинге вы отправляете код в суперклассы (чтобы исключить дублирование кода). Когда вы делаете такой рефакторинг, вы не теряете покрытие из-за того, что только один из ваших подклассов проверен на поведение его суперкласса.

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

...