Обновление : См. и этот вопрос.
Я могу ответить только на некоторые части здесь:
Можно ли сломать все зависимости, используя интерфейсы, только чтобы сделать класс тестируемым? Это приводит к значительным накладным расходам во время выполнения из-за множества виртуальных вызовов вместо простых вызовов методов.
Если ваша производительность из-за этого сильно пострадает, нет (тест!). Если ваше развитие страдает слишком много, нет (оцените дополнительные усилия). Если кажется, что это не будет иметь большого значения и поможет в долгосрочной перспективе и поможет вам с качеством, да.
Вы всегда можете «подружить» свои тестовые классы или объект TestAccessor, с помощью которого ваши тесты могут исследовать вещи внутри него. Это позволяет избежать динамической диспетчеризации всего лишь для тестирования. (это звучит как совсем немного работы.)
Разработка тестируемых интерфейсов не легка. Иногда вам нужно добавить несколько дополнительных методов, которые обращаются к внутренностям только для тестирования. Это заставляет вас немного съеживаться, но это полезно, и чаще всего эти функции полезны и в реальном приложении, рано или поздно.
Если я выполняю рефакторинг, очень часто случается, что мне приходится полностью перезаписывать юнит-тест из-за значительных логических изменений. Мои изменения кода очень часто меняют основную логику обработки данных. Я не вижу способа написания модульных тестов, которые не нужно менять при большом рефакторинге.
Большие рефакторинги по определению сильно меняются, включая тесты. Будьте счастливы, что они у вас есть, так как они будут проверять и после рефакторинга.
Если вы тратите больше времени на рефакторинг, чем на создание новых функций, возможно, вам следует подумать немного больше, прежде чем кодировать, чтобы найти лучшие интерфейсы, способные противостоять большему количеству изменений. Кроме того, написание юнит-тестов до того, как интерфейсы будут стабильными, - боль, независимо от того, что вы делаете.
Чем больше у вас кода для интерфейса, который сильно меняется, тем больше кода вам придется менять каждый раз. Я думаю, что ваша проблема лежит там. Мне удалось иметь достаточно стабильные интерфейсы в большинстве мест и время от времени реорганизовывать только детали.
Надеюсь, это поможет.