Кажется, что есть два совершенно разных подхода к тестированию, и я хотел бы привести их оба.
Дело в том, что эти мнения были высказаны 5 лет назад (2007), и мне интересно, что изменилось с тех пор и в каком направлении я должен идти.
Теория состоит в том, что тесты должны быть агностическими для реализация. Это приводит к менее хрупким испытаниям и фактически проверяет результат (или поведение).
С RSpec я чувствую, что общий подход полностью издевается над вашим модели для проверки ваших контроллеров в конечном итоге заставляют вас смотреть слишком много в реализацию вашего контроллера.
Это само по себе не так уж плохо, но проблема в том, что он тоже много в контроллер, чтобы диктовать, как используется модель. Почему это вопрос, если мой контроллер вызывает Thing.new? Что делать, если мой контроллер решает взять Thing.create! и спасательный маршрут? Что делать, если моя модель имеет специальный метод инициализации, например Thing.build_with_foo? Моя спецификация для поведение не должно прерываться, если я изменю реализацию.
Эта проблема становится еще хуже, когда у вас есть вложенные ресурсы и создание нескольких моделей на контроллер. Некоторые мои методы настройки завершаются до 15 или более линий длиной и ОЧЕНЬ хрупкой.
Цель RSpec - полностью изолировать логику вашего контроллера от ваши модели, которые звучат хорошо в теории, но почти идут против зерно для интегрированного стека, такого как Rails. Особенно, если вы практикуете тощий контроллер/жирная модельная дисциплина, количество логики в контроллер становится очень маленьким, и установка становится огромной.
Итак, что делать BDD-wannabe? Сделав шаг назад, поведение, которое я действительно хочу проверить не то, что мой контроллер вызывает Thing.new, но что при заданных параметрах X он создает новую вещь и перенаправляет на нее.
Дэвид Челимский:
Все о компромиссах.
Тот факт, что AR выбирает наследование, а не делегирование, ставит нас в привязка к тестированию - мы должны быть привязаны к базе данных ИЛИ мы должны быть более близким с реализацией. Мы принимаем этот выбор дизайна потому что мы пожинаем плоды в выразительности и суровости.
В борьбе с дилеммой я выбрал более быстрые тесты за счет немного более хрупким. Вы выбираете менее хрупкие тесты по цене из них работает немного медленнее. Его компромисс в любом случае.
На практике я запускаю тесты сотен, если не тысячи, раз день (я использую автотест и делаю очень подробные шаги), и я изменяю, Я использую "новый" или "создаю" почти никогда. Также из-за гранулированных стадий, новые модели, которые появляются, сначала являются волатильными. Действительный_что_attrs подход немного уменьшает боль от этого, но это все еще означает, что каждое новое обязательное поле означает, что я должен изменить valid_thing_attrs.
Но если ваш подход работает на вас на практике, тогда это хорошо! В факт, я настоятельно рекомендую опубликовать плагин с генераторами которые приводят примеры так, как вам нравятся. Я уверен, что много людей выиграют от этого.
Из любопытства, как часто вы используете mocks в своих тестах/спецификациях? Возможно, я делаю что-то неправильно, но я нахожу это серьезным ограничение. Начиная с перехода на rSpec более месяца назад, я делал что они рекомендуют в документах, где уровни контроллера и просмотра вообще не попадайте в базу данных, и модели полностью издеваются вне. Это дает вам хорошее ускорение скорости и облегчает некоторые вещи, но я нахожу, что минусы этого намного превосходят профессионалов. поскольку используя издевательства, мои спецификации превратились в кошмар для обслуживания. Спекуляции предназначены для проверки поведения, а не для реализации. Мне все равно если был вызван метод, я просто хочу убедиться, что полученный результат верно. Потому что насмешливая специфика реализации, он делает простые рефакторинги (которые не меняют поведение) невозможно без постоянного возвращения назад и "исправить" спецификации. Я очень убежден в том, что спецификация/тесты должны обложка. Тест прерывается только тогда, когда приложение ломается. Это один причина, по которой я вряд ли тестирую слой обзора, потому что считаю его слишком жестким. Это часто приводит к разрыву тестов без нарушения приложения. изменяя мелочи в представлении. Я нахожу ту же проблему с издевается. Помимо всего прочего, я сегодня понял, что насмешливое/прерывистое метод класса (иногда) держится между спецификациями. Спецификации должны быть автономным и не под влиянием других спецификаций. Это нарушает правило и приводит к сложным ошибкам. Что я узнал из всего этого? Быть осторожно, когда вы используете насмешку. Stubbing не так плохо, но все же некоторые из тех же проблем.
Я взял последние несколько часов и удалил почти все издевательства из моих спецификаций. Я также объединил контроллер и просмотрел спецификации в один, используя "integrate_views" в спецификации контроллера. Я также загружаю все светильники для каждой спецификации контроллера, поэтому есть некоторые тестовые данные для заполнения Виды. Конечный результат? Мои спецификации короче, проще, больше непротиворечивые, менее жесткие, и они проверяют весь стек вместе (модель, вид, контроллер), поэтому никакие ошибки не могут проскочить через трещины. я не говоря о том, что это "правильный" способ для всех. Если ваш проект требует очень строгой спецификации, тогда это может быть не для вас, но в моем это мир лучше, чем то, что у меня было до использования mocks. я по-прежнему думаю, что stubbing - хорошее решение в нескольких местах, поэтому я все еще делаю что.