Должен ли я удалять метод private/protected

Это на самом деле язык агностик. Но я дам вам контекст в python.

У меня этот родительский класс

class Mammal(object):
    def __init__(self):
        """ do some work """

    def eat(self, food):
        """Eat the food"""
        way_to_eat = self._eating_method()
        self._consume(food)

    def _eating_method(self):
        """Template method"""

    def _consume(self, food):
        """Template method"""

Здесь eat единственный публичный метод, тогда как _consume и _eating_method - фактически защищенные методы, которые будут реализованы дочерними классами.

Что вы проверите, когда напишете только класс Mammal?

Очевидно, все 4 метода.

Теперь представим ребенка

class Tiger(Mammal):    
    def _eating_method(self):
        """Template method"""

    def _consume(self, food):
        """Template method"""

Посмотрите на этот класс. Он имеет только 2 защищенных метода.

Должен ли я проверить все 4 метода Tiger (в том числе 2 унаследованных) или просто проверить введенные изменения (только переопределить 2 метода)?

Что такое идеальный случай?

Ответ 1

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

С прагматической точки зрения иногда вы можете иметь некоторые абстрактные вспомогательные классы без внедренного конкретного подкласса или абстрактного классового факторинга 90+% его дочерних классов и где было бы слишком сложно проверить результат без подключения к защищенному методу, В таких случаях вы можете издеваться над подклассом.

В вашем прямом примере я предлагаю вам протестировать только класс Tiger (и только общественный метод eat).

Просто примечание для людей, думающих о TDD. В TDD вы не должны были вводить код класса Mammal перед классом Tiger потому что Mammal должно быть результатом фазы рефакторинга. Итак, у вас, конечно же, нет специального теста для Mammal.

Ответ 2

Я бы подошел к этому:

  • Создайте минимальный проверяемый подкласс Mammal который обеспечивает минимальные реализации двух защищенных методов, которые позволяют вам тестировать поведение публичных методов.
  • Напишите отдельные модульные тесты для каждого подкласса, которые снова проверяют общедоступные методы для Mammal, но утверждают поведение, характерное для этого подкласса.

Это должно дать вам необходимое покрытие для тестирования с минимальным количеством тестов.

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

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

Ответ 3

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

Вы действительно заботитесь о поведении (потенциально абстрактного) суперкласса млекопитающих? Является ли отношение повторного использования к наследству важным? Что делать, если вы решили заменить отношения наследования на стратегию, основанную на составе?

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