Раньше мне не особо приходилось писать тесты, поэтому прошу простить, если слишком наивный вопрос.
Допустим у меня есть класс Klass, получающий на вход некоторые данные D, применяющий к ним некоторое преобразование f, а потом вызывающий какую-то сложную внешнюю обработку преобразованных данных g.
Klass::process(D) -> g(f(D));
Специфика класса такова, что:
1. функция f() — функция без побочных эффектов, кроме того в обозримом будущем подразумевается единственная реализация этой функции;
2. функция g() — какой-то сложный набор вызовов функций из API системы, точно так же планируется единственная реализации этой функции.
Теперь возникает потребность протестировать функцию f().
Для конкретики, программа пишется на C++. Сейчас ф-я f() — статическая в файле реализации класса. Таким образом, она не видна за пределами своей единицы трансляции, что замечательно само по себе, т.к. компилятор гарантирует, что эта функция не будет вызвана где-то ещё в другом месте.
Очевидные подходы:
1. Тестировать Klass через публичный интерфейс. Но тогда придётся выделять функцию g() в отдельный интерфейс и передавать в Klass как внешнюю зависимость, чтобы можно было заменить g() на fake_g(). Таким образом, резко усложнится структура класса, учитывая, что в реальной жизни будет использоватьcz единственная реализации функции g().
2. Вытащить функцию f() в отдельный файл. Но тогда получается, что мы теряем контроль компилятора за областью видимости этой функции.
3. Всякое хакерство типа #include Klass.cpp в тесте или #define private public там же, но это какое-то наркоманство. #include Klass.cpp плохо еще тем, что потащит за собой все инклюды из этого файла.
В общем, складывается ощущение, что "тестируемый" код либо стремится к какому-то переусложнению (трудность понимания, т.к. надо пробраться через все интерфейсы, добавленные исключительно ради возможности написать тест, прежде чем поймешь, что же происходит на самом деле), либо понижает пресловутую инкапсуляцию.
Как с этим жить?