Заметки с тегом
test
Как тестировать абстрактные классы

Абстрактные классы сложно тестировать. Рассмотрим ситуации применения абстрактных классов и последующего рефакторинга для проведения юнит тестирования.

Выделить реальный интерфейс

Существует специализированный абстрактный класс, но все клиенты используют его конкретные реализации через единый публичный интерфейс:

Классы-потомки реализуют интерфейс, определенный абстрактными методами класса. Для повышения тестируемости этот интерфейс выделяется. Абстрактный класс превращается в конкретный и в его конструктор передается объект классов-потомков, реализующих выделенный интерфейс.

Применяется шаблон проектирования стратегия.

Бывший абстрактный класс теперь тестируется используя мок-объект нового интерфейса. Все просто.

Выделить хелпер

Абстрактный класс используется для исключения повторений в наследуемых классах. Классы-потомки используются напрямую.

Абстрактный класс работает как хелпер (helper).

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

Базовый класс удаляется. Этот способ снова приводит дизайн к конкретным классам, которые просто и легко тестировать.

Совет

Предпочитайте сложную сеть простых объектов над простой сетью сложных. Ключ к трестируемому коду — маленькие строительные блоки и слабая связанность.

Комбинация ситуаций

Встречаются ситуации когда базовый класс содержит как публичный интерфейс, так и защищенные методы-помощники. В этом случае вспомогательные методы отправляются в один класс (ситуация 2), а для наследников реализуется шаблон стратегия (ситуация 1).

Когда в абстрактном классе часть методов виртуальные, а часть реализованные, еще возможно провести рефакторинг. Например, превратить классы наследники в стратегию. Но, такой случай — хороший индикатор, что ответственности требуют пересмотра.

Пишите в комментариях примеры когда сложно обойтись без абстрактного класса.