Дано программное обеспечение, где ...
- Система состоит из нескольких подсистем
- Каждая подсистема состоит из нескольких компонентов
- Каждый компонент реализован с использованием множества классов
... Мне нравится писать автоматические тесты для каждой подсистемы или компонента.
Я не пишу тест для каждого внутреннего класса компонента (за исключением того, что каждый класс вносит вклад в открытую функциональность компонента и поэтому тестируется / тестируется извне через открытый API компонента).
Когда я реорганизую реализацию компонента (что я часто делаю, как часть добавления новой функциональности), мне не нужно изменять какие-либо существующие автоматизированные тесты: потому что тесты зависят только от открытого API компонента, и общедоступные API обычно расширяются, а не изменяются.
Я думаю, что эта политика отличается от документа, подобного Рефакторинг кода теста , в котором говорится что-то вроде ...
- "... модульное тестирование ..."
- "... тестовый класс для каждого класса в системе ..."
- "... соотношение тестового кода / производственного кода ... в идеале считается равным 1: 1 ..."
... со всем, что, я полагаю, я не согласен (или, по крайней мере, не практикую).
Мой вопрос: если вы не согласны с моей политикой, объясните почему? В каких случаях этого уровня тестирования недостаточно?
В итоге:
- Публичные интерфейсы тестируются (и повторно тестируются) и редко меняются (они добавляются, но редко изменяются)
- Внутренние API скрыты за общедоступными API и могут быть изменены без переписывания тестовых примеров, которые проверяют общедоступные API
Сноска: некоторые из моих «контрольных примеров» фактически реализованы в виде данных. Например, контрольные примеры для пользовательского интерфейса состоят из файлов данных, которые содержат различные пользовательские входные данные и соответствующие ожидаемые системные выходные данные. Тестирование системы означает наличие тестового кода, который считывает каждый файл данных, воспроизводит ввод в систему и утверждает, что он получает соответствующий ожидаемый вывод.
Хотя мне редко нужно менять тестовый код (поскольку публичные API-интерфейсы обычно добавляются, а не изменяются), я обнаруживаю, что иногда (например, два раза в неделю) необходимо изменять некоторые существующие файлы данных. Это может случиться, когда я изменяю системный вывод в лучшую сторону (то есть новая функциональность улучшает существующий вывод), что может привести к сбою существующего теста (поскольку код теста только пытается утверждать, что вывод не изменился). Для обработки этих случаев я делаю следующее:
- Перезапустите автоматизированный набор тестов со специальным флагом времени выполнения, который говорит ему не утверждать вывод, а вместо этого захватывать новый вывод в новый каталог
- Используйте инструмент визуального сравнения, чтобы увидеть, какие файлы выходных данных (т.е. какие тестовые примеры) изменились, и убедиться, что эти изменения хороши и, как и ожидалось, с учетом новой функциональности
- Обновите существующие тесты, скопировав новые выходные файлы из нового каталога в каталог, из которого выполняются тестовые случаи (перезаписывая старые тесты)
Сноска: под "компонентом" я подразумеваю что-то вроде "одна DLL" или "одна сборка" ... что-то достаточно большое, чтобы его можно было увидеть в архитектуре или диаграмме развертывания системы, часто реализованной с использованием десятков или 100 классы, и с открытым API, который состоит только из 1 или нескольких интерфейсов ... что-то, что может быть назначено одной команде разработчиков (где другой компонент назначен другой команде), и поэтому будет в соответствии с Закон Конвея , имеющий относительно стабильный публичный API.
Сноска: статья Объектно-ориентированное тестирование: миф и реальность говорит,
Миф: достаточно проверки черного ящика.
Если вы делаете тщательную работу тестового случая
дизайн с использованием интерфейса класса илиспецификация, вы можете быть уверены, что
класс был полностью осуществлен.
Тестирование белого ящика (глядя на
реализация метода для проектирования
тесты) нарушает само понятие
инкапсуляция.
Реальность: ОО структура имеет значение, часть
II. Многие исследования показали, что
тесты черного ящика считаются
мучительно тщательный разработчиками
только упражнение от одной трети до половины
из утверждений (не говоря уже о путях или
штаты) в реализации под
тестовое задание. Есть три причины
этот. Во-первых, входы или состояния
выбрано обычно упражнение нормальное
пути, но не заставляйте все возможное
дорожки / состояния. Во-вторых, черный ящик
одно только тестирование не может выявить сюрпризов.
Предположим, мы проверили все
указанное поведение системы
под тестом. Чтобы быть уверенным, есть
нет неопределенного поведения, нам нужно
знать, есть ли какие-либо части системы
не использовался черным ящиком
тестирование. Единственный способ это
информацию можно получить по коду
измерительные приборы. В-третьих, это часто
трудно осуществить исключение и
обработка ошибок без проверки
исходный код.
Я должен добавить, что я выполняю функциональное тестирование whitebox: я вижу код (в реализации) и пишу функциональные тесты (которые управляют общедоступным API) для проверки различных ветвей кода (подробности реализации функции).