Прежде чем ответить на такой вопрос, вам нужно решить, чего вы на самом деле хотите достичь.
Вы пишете код. Вы надеетесь, что он выполнит свой контракт (другими словами, он делает то, что должен делать. Записать, что он должен делать, для некоторых людей - огромный шаг вперед).
Чтобы быть уверенным в том, что код выполняет то, что он должен делать, вы либо пристально смотрите на него, либо пишете тестовый код, который проверяет достаточно случаев, чтобы убедить вас, «если код пройдет все эти тесты, тогда он верен».
Часто вас интересует только публично определенный интерфейс какого-то кода. Если я использую свою библиотеку, я не волнует , как вы сделали это правильно работать, только то , что он делает работу правильно. Я проверяю правильность вашей библиотеки, выполняя модульные тесты.
Но вы создаете библиотеку. Заставить его работать правильно может быть трудно достичь. Допустим, меня заботит только то, что библиотека выполняет операцию X правильно, поэтому у меня есть модульный тест для X. Вы, разработчик, отвечающий за создание библиотеки, реализуете X, комбинируя шаги A, B и C, каждый из которых абсолютно нетривиален. Чтобы ваша библиотека работала, вы добавляете тесты, чтобы убедиться, что A, B и C работают правильно. Вы хотите эти тесты. Говорить «у вас не должно быть юнит-тестов для частных методов» - совершенно бессмысленно. Вы хотите тесты для этих частных методов. Может быть, кто-то скажет вам, что юнит-тестирование приватных методов неверно. Но это только означает, что вы можете называть их не «модульными тестами», а «частными тестами» или как вы их называете.
Язык Swift решает проблему, заключающуюся в том, что вы не хотите выставлять A, B, C как публичные методы только потому, что вы хотите протестировать его, предоставив функциям атрибут «testable». Компилятор позволяет вызывать закрытые тестируемые методы из модульных тестов, но не из не тестового кода.