Единичное тестирование частных методов в Xcode

Я пытаюсь разработать тест-драйв в игрушечном проекте. Я могу заставить тесты работать для открытого интерфейса с моими классами (хотя я все еще нахожусь на заборе, потому что я пишу больше кода тестирования, чем в тестируемых методах).

Я склонен использовать множество частных методов, потому что мне нравится чинить публичные интерфейсы; однако, я все еще хотел бы использовать тесты этих методов.

Так как Cocoa является динамическим языком, я все равно могу вызвать эти частные методы, но я получаю предупреждения в своих тестах, что мой класс не может реагировать на эти методы (хотя это ясно). Поскольку мне нравится компилироваться без предупреждений, вот мои вопросы:

  • Как отключить эти предупреждения в Xcode?
  • Есть ли что-то еще, что я могу сделать, чтобы отключить эти предупреждения?
  • Я делаю что-то неправильно в попытке тестирования "белого ящика"?

Ответ 1

Как отключить эти предупреждения в Xcode?

Не.

Есть ли что-то еще, что я могу сделать, чтобы отключить эти предупреждения?

Не.

Я делаю что-то неправильно в попытке тестирования "белого ящика"?

Нет.

Решение состоит в том, чтобы переместить ваши частные методы в категорию в свой собственный заголовок. Импортируйте этот заголовок как в реальные, так и в тестовые файлы реализации класса.

Ответ 2

Помните, что на самом деле нет такой вещи, как "частные методы" в Objective-C, и это не только потому, что это динамический язык. По дизайну Objective-C есть модификаторы видимости для ivars, но не для методов - это не случайно, что вы можете вызвать любой метод, который вам нравится.

Предложение

@Peter - отличное решение. В дополнение к его ответу, альтернатива, которую я использовал (когда мне не нужен/нужен заголовок только для частных методов), это объявить категорию в самом файле unit test. (Я использую @interface MyClass (Test) как имя.) Это отличный способ добавить методы, которые были бы излишним раздуванием в коде выпуска, например, для доступа к иварам, к которым имеет доступ класс тестирования. (Это явно не проблема при использовании свойств.)

Я нашел этот подход, который позволяет легко выявлять и проверять внутреннее состояние, а также добавлять методы только для тестирования. Например, в этот unit test файл я написал метод -isValid для проверки правильности двоичной кучи. В производстве этот метод был бы пустой тратой пространства, так как я предполагаю, что куча действительна - мне все равно, когда она тестирует регрессии unit test, если я изменяю код.

Ответ 4

Хотя наличие частного заголовка или определение вашей собственной категории, вероятно, являются более правильными решениями, есть еще одно очень простое решение: перед тем, как вызывать метод, отбросьте объект (id).

Ответ 5

Если вы не хотите распространять свои частные реализации методов в нескольких исходных файлах, уточнение для решения категории заключается в определении расширения (по существу анонимной категории - см. Документация Apple) в файле заголовка, который импортируется как реализацией существующего класса, так и соответствующими исходными файлами unit test.

Использование расширения позволяет компилятору предупредить вас, если реализация частного метода отсутствует в основном блоке @implementation. Эта ссылка хорошо иллюстрирует это.

Ответ 6

Я имел дело с той же проблемой, когда я начал с TDD несколько дней назад. Я нашел эту очень интересную точку зрения в Test-Driven iOS Development:

Меня часто спрашивали: "Я должен проверить свои личные методы?" или связанный с ним вопрос "Как проверить мои личные методы?" Люди, задающие второй вопрос, предположили, что ответ на первый вопрос - "Да", и теперь ищут способ разоблачить свои классы частных интерфейсов в своих тестовых наборах.

Мой ответ основан на наблюдении тонкого факта: вы уже проверили свои частные методы. Следуя принципу red-green-refactor, обычно используемому в тестовой разработке, вы разработали свои общедоступные API-интерфейсы для работы, которые должны выполнять эти объекты. С той работой, указанной в тестах, и продолжением выполнения тестов, гарантирующих, что вы ничего не сломаете, вы можете организовать внутреннюю сантехнику ваших классов по своему усмотрению.

Ваши частные методы уже протестированы, потому что все, что вы делаете, - это поведение рефакторинга, к которому у вас уже есть тесты. Вы никогда не должны заканчиваться в ситуации, когда частный метод не проверен или не полностью проверен, потому что вы создаете его только тогда, когда вы видите возможность очистить реализацию общедоступных методов. Это гарантирует, что частные методы существуют только для поддержки классов, которые они должны вызывать во время тестирования, потому что они определенно вызываются из общедоступных методов.

Ответ 7

Простая работа. шаги: 1. У вас есть - (NSString *) getTestString; в вашем целевом файле m для интерфейса Foo

  1. Добавьте категорию в свой unit test файл:

    @interface DemoHomeViewController() - (NSString *) getTestString; @end

Затем сделайте все, что вам нужно.