Когда вы используете композицию, вы можете издеваться над другими объектами. от которого зависит ваш тестируемый класс, но когда вы используете наследование, вы не можете издеваться над базовым классом. (Или ты можешь?)
Я вообще стараюсь предпочитать композицию наследованию, но иногда наследование действительно кажется лучшим инструментом для работы - ну, по крайней мере, до модульного тестирования.
Итак, как проверить наследование? Или вы просто выбрасываете его как непроверяемый и вместо этого использовать композицию?
Примечание: Я в основном использую PHP и PHPUnit, так что помогите с этой стороны очень ценится. Но было бы также интересно узнать если есть решения этой проблемы на других языках.
Я не понимаю, как можно издеваться над суперклассом. Это должна быть языковая функция ihmo. Что именно вы пытаетесь проверить? Мне кажется, размышления могут быть вам полезны?
Я также не знаю, как можно было бы издеваться над родительским классом. Вот почему я спрашиваю. Но я не думаю, что это невозможно - в компьютерах очень мало вещей.
Я все еще не понимаю ваших требований. Что не так / что не хватает, если вы тестируете методы суперкласса с их собственными модульными тестами, а затем методы подкласса с их собственными, отдельными тестами? Похоже, вы хотите снова протестировать методы суперкласса в тестах для подкласса? Зачем вам это нужно? Или я что-то упускаю
@Robse Это работает только тогда, когда подкласс просто добавляет новые методы, не отменяя ни один из методов родительского класса. Но когда я переопределяю метод в суперклассе, мне нужно одновременно убедиться, что новый метод теперь изменяет поведение суперкласса должным образом, и в то же время не портит поведение, на которое он не должен влиять.






Пока вы не переопределяете общедоступные методы родительского класса, я не понимаю, почему вам нужно тестировать их на всех его подклассах. Модульное тестирование методов родительского класса и тестирование только новых методов или переопределенных методов в подклассах.
Зачем издеваться над базовым классом?
Как вы можете создавать производные классы из несуществующего родительского класса?
Просто протестируйте его как обычно, но оставьте родительский класс.
Я думаю, вы не рассказали всю историю.
Кроме того, предполагается, что языковые функции работают (если вы не работаете с бета-версиями или около того), поэтому вам не нужно проверять, действительно ли метод существует в производном классе.
Причина, по которой вы используете фиктивные объекты в композиции, заключается в том, что реальные объекты делают что-то, что вы не хотите настраивать (например, используют сокеты, последовательные порты, получают ввод пользователя, извлекают объемные данные и т. д.). По возможности всегда следует использовать реальные объекты. Мок-объекты предназначены только для тех случаев, когда предполагаемые усилия по реализации и сопровождению теста с использованием реального объекта больше, чем усилия по реализации и сопровождению теста с использованием фиктивного объекта. Ваш базовый класс не должен делать ничего подобного!
Так что вам не нужно проверять наследование. Предположительно, вы используете поведение базового класса, поэтому просто протестируйте производный класс, как обычно, - вызывая методы как для базового, так и для производного класса в соответствии с требованиями теста. Это гарантирует, что все предполагаемое поведение производного класса проверено.
По сути (большую часть времени) вы тестируете производный класс так, как будто базовый класс невидим.
Нет, не знаешь. Вам просто нужно проверить, что методы переопределения делают то, что должны. Это НИКОГДА не должно влиять на поведение ваших родительских методов. Если ваши родительские методы начинают давать сбой, это означает, что вы пропустили связанные условия при их тестировании на родительском уровне.
Вы правы, и я тоже на это указываю! Пока вы переопределяете метод в подклассе, вам НЕОБХОДИМО его модульное тестирование. Тот факт, что он вызывает родительский метод или нет, не имеет значения, просто проверьте, что результат метода подкласса - тот, который вы ожидаете, а также родительский метод ведет себя так, как вы этого хотите. Более того, как указывает @metao, в вашем родительском классе нет дополнительной настройки состояния, которую вы не поймали в своем подклассе. И если это произойдет, вам следует пересмотреть использование композиции вместо наследования.
Я полностью согласен с тем, что методы подкласса не должны влиять на поведение методов родительского класса. Вот почему я избегал доступа к переменным-членам родительского класса и использовал только его общедоступный интерфейс. Но когда метод подкласса вызывает метод в родительском классе, тогда при тестировании метода подкласса я также заканчиваю тестирование метода родительского класса.
Используйте набор модульных тестов, отражающих иерархию классов. Если у вас есть базовый класс Base и производный класс Derived, тогда имейте тестовые классы BaseTests и производные от этих DerivedTests. BaseTests отвечает за тестирование всего, что определено в Base. DerivedTests наследует эти тесты, а также отвечает за тестирование всего в Derived.
Если вы хотите протестировать защищенные виртуальные методы в Base (т.е. интерфейс между Base и его дочерними классами), также может иметь смысл создать производный класс только для тестирования, который проверяет этот интерфейс.
Для решение, данное великодушным есть хороший пример. Пусть тестовая иерархия будет напоминать вашу иерархию классов.