Я ценю, что на этот вопрос задавали и отвечали почти год назад, но я не могу не согласиться с данными ответами. Тестирование асинхронных операций, особенно сетевых операций, является очень распространенным требованием и важно, чтобы получить правильные результаты. В данном примере, если вы зависите от реальных сетевых ответов, вы теряете некоторые важные значения ваших тестов. В частности, ваши тесты становятся зависимыми от доступности и функциональной корректности сервера, с которым вы общаетесь; эта зависимость делает ваши тесты
- более хрупкий (что произойдет, если сервер выйдет из строя?)
- менее полно (как вы последовательно тестируете реакцию на ошибку или сетевую ошибку?)
- значительно медленнее, представьте себе тестирование:
Модульные тесты должны выполняться за доли секунды. Если вам приходится каждый раз ждать, пока вы будете выполнять тесты, ждать ответа по сети в течение нескольких секунд, то вы вряд ли будете часто их запускать.
Модульное тестирование в основном сводится к инкапсуляции зависимостей; с точки зрения тестируемого кода происходят две вещи:
- Ваш метод инициирует сетевой запрос, возможно, путем создания NSURLConnection.
- Указанный вами делегат получает ответ через определенные вызовы методов.
Ваш делегат не заботится или не должен заботиться о том, откуда пришел ответ, будь то фактический ответ с удаленного сервера или ваш тестовый код. Вы можете воспользоваться этим для проверки асинхронных операций, просто генерируя ответы самостоятельно. Ваши тесты будут выполняться намного быстрее, и вы сможете надежно тестировать ответы об успехах или ошибках.
Это не значит, что вы не должны запускать тесты для реального веб-сервиса, с которым вы работаете, но это интеграционные тесты, которые принадлежат их собственному тестовому набору. Сбои в этом наборе могут означать, что веб-служба изменилась или просто не работает. Поскольку они более хрупкие, их автоматизация имеет меньшую ценность, чем автоматизация ваших юнит-тестов.
Относительно того, как именно выполнить тестирование асинхронных ответов на сетевой запрос, у вас есть несколько вариантов. Вы можете просто протестировать делегат изолированно, вызывая методы напрямую (например, [someDelegate connection: connection didReceiveResponse: someResponse]). Это будет работать несколько, но немного неправильно. Делегат, предоставляемый вашим объектом, может быть только одним из нескольких объектов в цепочке делегатов для конкретного объекта NSURLConnection; если вы вызываете методы вашего делегата напрямую, вам может не хватать какой-то ключевой части функциональности, предоставляемой другим делегатом в дальнейшей цепочке. В качестве лучшей альтернативы вы можете создать заглушку созданного вами объекта NSURLConnection и отправить ему ответные сообщения по всей цепочке делегатов. Существуют библиотеки, которые откроют NSURLConnection (среди других классов) и сделают это для вас. Например: https://github.com/pivotal/PivotalCoreKit/blob/master/SpecHelperLib/Extensions/NSURLConnection%2BSpec.m