Ответ 1
TL;DR
В Pivotal мы написали Cedar, потому что мы используем и любим Rspec в наших проектах Ruby. Кедр не предназначен для замены или конкуренции с OCUnit; это означало возможность тестирования BDD-стиля на Objective C, так же как Rspec впервые испытал BDD-стиль в Ruby, но не исключил Test:: Unit. Выбор того или другого во многом зависит от предпочтений стиля.
В некоторых случаях мы разработали Cedar для преодоления некоторых недостатков в том, как OCUnit работает для нас. В частности, мы хотели иметь возможность использовать отладчик в тестах, запускать тесты из командной строки и сборок CI и получать полезный текстовый вывод результатов теста. Эти вещи могут быть более или менее полезными для вас.
Длинный ответ
Решение двух структур тестирования, таких как Cedar и OCUnit (например), сводится к двум вещам: предпочтительный стиль и простота использования. Я начну с стиля, потому что это просто вопрос мнения и предпочтения; легкость использования, как правило, представляет собой набор компромиссов.
Приоритеты стиля превосходят ту технологию или язык, которые вы используете. Модульное тестирование в стиле xUnit прошло гораздо дольше, чем тестирование в стиле BDD, но последнее быстро завоевало популярность, в основном благодаря Rspec.
Основным преимуществом тестирования в стиле xUnit является его простота и широкое внедрение (среди разработчиков, которые пишут единичные тесты); почти любой язык, на котором вы могли бы подумать о написании кода, имеет доступную инфраструктуру стиля xUnit.
Структуры в стиле BDD имеют два основных отличия по сравнению с xUnit-style: как вы структурируете тест (или спецификации) и синтаксис для написания ваших утверждений. Для меня структурное различие является основным отличием. Тесты xUnit являются одномерными, с одним методом setUp для всех тестов в данном тестовом классе. Однако классы, которые мы тестируем, не одномерны; нам часто приходится тестировать действия в нескольких разных, потенциально конфликтных контекстах. Например, рассмотрим простой класс ShoppingCart с методом addItem: (для целей этого ответа я использую синтаксис Objective C). Поведение этого метода может различаться, если тележка пуста по сравнению с тем, когда в корзине есть другие предметы; он может отличаться, если пользователь ввел код скидки; он может отличаться, если указанный элемент не может быть отправлен выбранным способом доставки; и т.д. Поскольку эти возможные условия пересекаются друг с другом, вы получаете геометрически увеличивающееся число возможных контекстов; при тестировании в стиле xUnit это часто приводит к множеству методов с такими именами, как testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. Структура фреймворков в стиле BDD позволяет организовать эти условия индивидуально, что, по моему мнению, упрощает проверку всех случаев, а также позволяет легко находить, изменять или добавлять отдельные условия. В качестве примера, используя синтаксис Cedar, метод выше будет выглядеть так:
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
В некоторых случаях вы найдете контексты, в которых содержатся те же самые множества утверждений, которые вы можете DRY с использованием общих контекстов примеров.
Второе основное отличие между фреймами в стиле BDD и фреймворками стиля xUnit, синтаксисом assertion (или "matcher" ) просто упрощает стиль спецификаций; некоторым людям это очень нравится, другие - нет.
Это приводит к вопросу о простоте использования. В этом случае каждая структура имеет свои плюсы и минусы:
-
OCUnit работает гораздо дольше, чем Cedar, и интегрируется непосредственно в Xcode. Это означает, что просто создать новую целевую аудиторию и, в большинстве случаев, получать тесты и работать "просто работает". С другой стороны, мы обнаружили, что в некоторых случаях, например, запуск на устройстве iOS, получение тестов OCUnit практически невозможно. Настройка спецификаций Cedar требует больше работы, чем тесты OCUnit, поскольку вы сами получили библиотеку и ссылку против нее (никогда не тривиальная задача в Xcode). Мы работаем над упрощением настройки, и любые предложения более чем приветствуются.
-
OCUnit запускает тесты как часть сборки. Это означает, что вам не нужно запускать исполняемый файл, чтобы выполнить ваши тесты; если какие-либо тесты не пройдут, ваша сборка завершится неудачно. Это упрощает процесс прогона тестов на один шаг, а тестовый вывод поступает непосредственно в окно вывода сборки, что упрощает его просмотр. Мы решили использовать спецификации Cedar в исполняемом файле, который вы запускаете отдельно по нескольким причинам:
- Мы хотели иметь возможность использовать отладчик. Вы запускаете спецификации Cedar так же, как вы запускаете любой другой исполняемый файл, так что вы можете использовать отладчик таким же образом.
- Нам нужно было просто вести ведение журнала в тестах. Вы можете использовать NSLog() в тестах OCUnit, но вывод идет в окно сборки, где вам нужно развернуть шаг сборки, чтобы прочитать его.
- Мы хотели легко прочитать тестовую отчетность, как в командной строке, так и в Xcode. Результаты OCUnit хорошо видны в окне построения в Xcode, но построение из командной строки (или как часть процесса CI) приводит к выходу теста, смешанному с множеством других результатов сборки. С отдельными этапами сборки и запуска Cedar отделяет выход так, что тестовый выход легко найти. По умолчанию тестовый бегун Cedar копирует стандартный стиль печати ".". для каждой пропущенной спецификации, "F" для неудачных спецификаций и т.д. Cedar также имеет возможность использовать пользовательские объекты-репортеры, поэтому вы можете получить результаты вывода любым способом, как вам нравится, с небольшими усилиями.
-
OCUnit является официальной платформой тестирования модулей для Objective C и поддерживается Apple. Apple имеет в основном неограниченные ресурсы, поэтому, если они хотят что-то сделать, это будет сделано. И, в конце концов, это песочница Apple, в которой мы играем. Оборотная сторона этой монеты, однако, заключается в том, что Apple получает по заказу запросов на поддержку bajillion и отчетов об ошибках каждый день. Они отлично справляются с обработкой их всех, но они могут не справиться с проблемами, о которых вы сообщаете немедленно или вообще. Кедр намного более новый и менее испеченный, чем OCUnit, но если у вас есть вопросы или проблемы или предложения, отправьте сообщение в список рассылки Cedar ([email protected]), и мы сделаем все возможное, чтобы помочь вам. Кроме того, не стесняйтесь разворачивать код из Github (github.com/pivotal/cedar) и добавлять все, что, по вашему мнению, отсутствует. Мы создаем основы тестирования с открытым исходным кодом по какой-либо причине.
-
Запуск тестов OCUnit на устройствах iOS может быть затруднен. Честно говоря, я не пробовал это в течение довольно долгого времени, поэтому, возможно, это стало проще, но в последний раз, когда я пытался, я просто не мог получить тесты OCUnit для любых функций UIKit. Когда мы писали Cedar, мы убедились, что можем тестировать код, зависящий от UIKit, как на симуляторе, так и на устройствах.
Наконец, мы написали Cedar для модульного тестирования, что означает, что он не очень сопоставим с такими проектами, как UISpec. Прошло довольно много времени с тех пор, как я попытался использовать UISpec, но я понял, что это основное внимание уделяется программному управлению пользовательским интерфейсом на устройстве iOS. Мы специально решили не пытаться, чтобы Cedar поддерживала эти типы спецификаций, так как Apple (в то время) собиралась объявить UIAutomation.