Речь идет не только о публичных или частных методах или функциях, но и о деталях реализации. Частные функции - это только один аспект деталей реализации.
В конце концов, модульное тестирование - это метод тестирования белого ящика. Например, тот, кто использует анализ покрытия для определения частей кода, которые до сих пор игнорировались при тестировании, углубляется в детали реализации.
A) Да, вы должны тестировать детали реализации:
Подумайте о функции сортировки, которая по соображениям производительности использует частную реализацию BubbleSort, если имеется до 10 элементов, и частную реализацию другого подхода сортировки (скажем, heapsort), если имеется более 10 элементов. Публичный API - это функция сортировки. Однако ваш набор тестов лучше использует знания о том, что на самом деле используются два алгоритма сортировки.
В этом примере, безусловно, вы можете выполнить тесты с открытым API. Это, однако, потребует наличия нескольких тестовых случаев, которые выполняют функцию сортировки с более чем 10 элементами, так что алгоритм heapsort достаточно хорошо протестирован. Наличие таких тестовых примеров само по себе указывает на то, что набор тестов связан с деталями реализации функции.
Если детали реализации функции сортировки изменятся, возможно, из-за того, что предел между двумя алгоритмами сортировки будет смещен, или что heapsort будет заменен слиянием или что-то еще: существующие тесты продолжат работать. Тем не менее, их ценность сомнительна, и их, вероятно, необходимо переработать, чтобы лучше протестировать измененную функцию сортировки. Другими словами, будут предприняты усилия по обслуживанию, несмотря на тот факт, что тесты проводились на общедоступном API.
B) Как проверить детали реализации
Одна из причин, почему многие люди утверждают, что не следует тестировать частные функции или детали реализации, состоит в том, что детали реализации с большей вероятностью изменятся. Эта более высокая вероятность изменений, по крайней мере, является одной из причин скрытия деталей реализации за интерфейсами.
Теперь предположим, что реализация интерфейса содержит более крупные закрытые части, для которых могут использоваться отдельные тесты внутреннего интерфейса. Некоторые люди утверждают, что эти части не должны быть проверены в частном порядке, они должны быть превращены во что-то публичное. После публичного юнит-тестирования этот код будет в порядке.
Это интересно: хотя интерфейс был внутренним, он, скорее всего, изменится, будучи деталью реализации. Взяв тот же интерфейс, сделав его общедоступным, произойдет некое волшебное преобразование, а именно превращение его в интерфейс, который с меньшей вероятностью изменится. Очевидно, в этой аргументации есть некоторый недостаток.
Но, тем не менее, за этим стоит некоторая правда: при тестировании деталей реализации, в частности с использованием внутренних интерфейсов, следует стремиться использовать интерфейсы, которые, вероятно, останутся стабильными. Однако вероятность того, что какой-либо интерфейс будет стабильным, не просто зависит от того, является ли он общедоступным или закрытым. В проектах из мира, в которых я работал в течение некоторого времени, публичные интерфейсы также достаточно часто меняются, и многие частные интерфейсы остаются неизменными целую вечность.
Тем не менее, это хорошее эмпирическое правило использовать «переднюю дверь первой» (см. http://xunitpatterns.com/Principles%20of%20Test%20Automation.html). Но имейте в виду, что она называется «передняя дверь первой», а не «только передняя дверь».
C) Резюме
Проверьте также детали реализации. Предпочитают тестирование на стабильных интерфейсах (публичных или приватных). Если детали реализации меняются, также необходимо пересмотреть тесты общедоступного API. Превращение чего-то частного в публичное не может волшебным образом изменить его стабильность.