Допустим, в соответствии с принципом разделения ответственности я выделил много маленьких функций, решающих свои задачи, и покрыл их тестами. Но ведь есть и некая общая функция, которая вызывает эти маленькие.
Как тестировать эту общую функцию? Ведь она покрывает все возможные варианты исполнения кода в этих маленьких функциях.
Не тестировать её вовсе, так как вся функциональность протестирована уже в маленьких функциях? Так нельзя - а вдруг я написал эту большую функцию неверно (вызвал маленькие не в той последовательности или забыл что-то). Тесты нужны, вопрос лишь, какие.
Так же интересует, как тестировать функции с побочными эффектами. Да, я знаю про внедрение зависимостей, но получается его нужно использовать всегда-всегда, чтобы тестирование было возможным? Не усложнит ли это код, не сделает ли его более запутанным и нечитаемым?
* * *
Ну и чтобы было понятнее, приведу конкретный пример. Предположим, нам нужно обработать аргументы командной строки, передаваемые в программу. А именно:
- при наличии аргумента
-v
вывести версию;
- провалидировать значения остальных аргументов (скажем, что они попадают в определённые лимиты или входят в указанный список).
Мы написали функцию для этого (некий абстрактный псевдоязык):
function ProcessArgs(args) {
let parsed_args = ParseArgs(args)
ShowVersionIfNeed(parsed_args)
ValidateValues(parsed_args)
return parsed_args
}
Причём, функции
ParseArgs()
,
ShowVersionIfNeed()
и
ValidateValues()
тоже реализованы и, что важно, покрыты тестами.
Вопрос - как нужно тестировать функцию
ProcessArgs()
? Перебирать все возможные варианты для всех внутренних функций? То есть по сути перебирать все написанные для них тесты во всех возможных сочетаниях? Или как?
И второй вопрос. Вот функция
ShowVersionIfNeed()
:
function ShowVersionIfNeed(args) {
if args.contains('-v') {
sys.Exit(sys.ExitSuccess)
}
}
Как видим, в ней есть прерывание программы. Как такое тестировать? Её запуск нарушит работу всех остальных тестов же.
Добавить внедрение зависимостей?
function ProcessArgs(args, exiter) {
let parsed_args = ParseArgs(args)
ShowVersionIfNeed(parsed_args, exiter)
ValidateValues(parsed_args)
return parsed_args
}
function ShowVersionIfNeed(args, exiter) {
if args.contains('-v') {
exiter.Exit(sys.ExitSuccess)
}
}
Но это же усложняет и запутывает код. Или нет и так делать нормально и правильно?