Что не тестировать в Rails? - PullRequest
13 голосов
/ 02 сентября 2010

Я уже некоторое время пишу тесты, и я начинаю разбираться в вещах. Но у меня есть несколько вопросов относительно того, сколько тестового покрытия действительно необходимо. Консенсус кажется довольно ясным: больший охват всегда лучше. Но, по крайней мере, с точки зрения начинающего, интересно, правда ли это.

Возьмем это полностью ванильное действие контроллера, например:

def create
  @event = Event.new(params[:event])
  if @event.save
    flash[:notice] = "Event successfully created."
    redirect_to events_path
  else
    render :action => 'new'
  end
end

Только сгенерированные леса. Мы не делаем ничего необычного здесь. Почему важно писать тесты контроллера для этого действия? В конце концов, мы даже не написали код - генератор сделал всю работу за нас. Если в рельсах нет ошибки, этот код должен быть в порядке. Кажется, что тестирование этого действия не слишком отличается от тестирования, скажем, collection_select - и мы бы этого не делали. Кроме того, предполагая, что мы используем огурец, мы уже должны покрыть основы (например, куда он перенаправляет).

То же самое можно сказать и о простых модельных методах. Например:

def full_name
  "#{first_name} #{last_name}"
end

Нам действительно нужно писать тесты для таких простых методов? Если есть синтаксическая ошибка, вы поймете ее при обновлении страницы. Точно так же cucumber поймает это, если ваши функции попадут на любую страницу, которая вызвала метод full_name. Очевидно, мы не должны полагаться на огурец для чего-то слишком сложного. Но действительно ли полное_имя нуждается в модульном тесте?

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

Но, как я уже сказал, я вряд ли опытный тестировщик. Я не обязательно защищаю меньшее тестовое покрытие. Скорее, я ищу совет специалиста. Есть ли хорошая причина писать такие простые тесты?

Ответы [ 5 ]

9 голосов
/ 02 сентября 2010

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

Для меня тесты облегчают три вещи:

  1. Они гарантируют непрерывную старую функциональность Если я смогу проверить это ничего нового, что я вставил, не сломалось мои старые вещи, запустив тесты, это хорошая вещь.

  2. Они заставляют меня чувствовать себя в безопасности, когда я переписываю старые вещи Код, который я Реактор очень редко тривиальный один. Если, однако, я хочу рефакторинг нетривиальный код, имеющий тесты для убедитесь, что мои рефакторинги не имеют нарушено любое поведение является обязательным.

  3. Это документация моей работы Нетривиальный код должен быть документированы. Если, однако, вы согласны со мной, что комментарии в коде является работа дьявола, имея четкое и краткие юнит-тесты, которые делают вас понять что такое правильное поведение что-то, является (опять же) обязательным.

Все, что я уверен, что не сломаю, или то, что я считаю ненужным документировать, я просто не трачу время на тестирование. Тогда ваши сгенерированные контроллеры и методы модели, я бы сказал, все в порядке, даже без юнит-тестов.

6 голосов
/ 25 ноября 2013

Единственное абсолютное правило - тестирование должно быть рентабельным.

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

блок

  • Не тестируйте частные методы напрямую, только оцените их влияние косвенно через открытые методы, которые их вызывают.
  • Не проверять внутренние состояния
  • Только тестировать нетривиальные методы , где разные контексты могут получать разные результаты (вычисления, конкатенация, регулярные выражения, ветви ...)
  • Не оценивайте вещи, которые вас не волнуют , например полная копия некоторых сообщений или ненужных частей сложных структур данных, возвращаемых API ...
  • Заглушите все элементы в модульных тестах , они называются модульными тестами, потому что вы тестируете только один класс, а не его соавторов. С помощью заглушек / шпионов вы проверяете отправленные сообщения, не проверяя их внутреннюю логику.
  • Рассматривать частные вложенные классы как частные методы

Интеграция

  • Не пытайтесь проверять все комбинации в интеграционных тестах. Вот для чего предназначены юнит-тесты. Просто протестируйте счастливые пути или наиболее распространенные случаи.
  • Не используйте огурец, если вы действительно не BDD
  • Интеграционные тесты не всегда нужно запускать в браузере. Чтобы тестировать больше случаев с меньшим падением производительности, некоторые интеграционные тесты могут взаимодействовать напрямую с классами моделей.
  • Не проверяйте то, чем вы не владеете. Интеграционные тесты должны ожидать, что сторонние зависимости будут выполнять свою работу, но не заменять собственный набор тестов.

Контроллер

  • В тестах контроллера, только тестировать логику контроллера : перенаправления, аутентификация, разрешения, статус HTTP. Заглушка бизнес логика. Рассмотрим фильтры и т. Д., Например, закрытые методы в модульных тестах, протестированные только с помощью действий открытого контроллера.

Другие

  • Не писать тесты маршрутов , за исключением случаев, когда вы пишете API, для конечных точек, еще не охваченных интеграционными тестами.
  • Не писать тесты вида . Вы должны иметь возможность изменять классы копирования или HTML, не нарушая свои тесты. Просто оцените критические элементы представления как часть ваших интеграционных тестов в браузере.
  • Протестируйте свой клиент JS , особенно если он содержит некоторую логику приложения. Все эти правила также применимы к тестам JS.

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

Подробнее об этом сообщении .

6 голосов
/ 03 сентября 2010

Чем больше охват, тем лучше качество кода, но это стоит дороже.Здесь есть скользящая шкала, если вы кодируете искусственное сердце, вам нужно больше тестов.Чем меньше вы платите авансом, тем выше вероятность того, что вы заплатите позже, возможно, болезненно.

В примере полное_имя, почему вы поместили пробел между и упорядочены по first_name, а затем по last_name - это имеет значение?Если позже вас попросят отсортировать по фамилии, можно ли поменять местами ордер и добавить запятую?Что, если фамилия состоит из двух слов - это дополнительное пространство повлияет на вещи?Может быть, у вас также есть XML-фид, который кто-то еще анализирует?Если вы не уверены, что тестировать, для простой недокументированной функции, возможно, подумайте о функциональности, подразумеваемой именем метода.

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

Некоторые люди используют подход тестирования крайних случаев и предполагают, что основные функции будут работатьчерез использование.Что касается getter / setters, я бы хотел где-нибудь класс модели, в котором есть несколько тестов для этих методов, возможно, для проверки диапазонов типов столбцов базы данных.По крайней мере, это говорит о том, что с сетью все в порядке, соединение с базой данных может быть установлено, у меня есть доступ для записи в существующую таблицу и т. Д. Страницы приходят и уходят, поэтому не следует рассматривать загрузку страницы как замену действительноймодульный тест.(Примечание по эффективности тестирования - если автоматическое тестирование основано на отметке времени обновления файла (автотест), этот тест не запустится, и вы хотите знать как можно скорее)

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

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

100% охватне должно быть вашей целью - хорошее тестирование должно быть.Было бы заблуждением думать, что один тест регулярного выражения выполняет что-либо.Я предпочел бы не проводить тесты, чем один, потому что мой автоматический отчет о покрытии напоминает мне, что RE ненадежен.

5 голосов
/ 02 сентября 2010

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

Стоит ли того усилий или нет, зависит от вас.

Вторым преимуществом, которое я вижу, глядя на него, будет тестирование крайних случаев, например, что он должен делать, если last_name равен "" или nil. Это может выявить неожиданное поведение.

(то есть, если last_name равно nil, а first_name равно "John", вы получите full_name => "John ")

Опять же, цена-выгода в конечном итоге зависит от вас.

1 голос
/ 02 сентября 2010

Для сгенерированного кода нет необходимости тестовое покрытие, потому что, как вы сказали, вы его не писали. Если есть проблема, она выходит за рамки тестов, которые должны быть сосредоточены на вашем проекте. Точно так же вам, вероятно, не потребуется явно тестировать библиотеки, которые вы используете.

Для вашего конкретного метода это выглядит как эквивалент метода установки (это было немного с тех пор, как я создал Ruby on Rails) - тестирование этого метода будет проверять возможности языка. Если вы меняли значения или генерировали выходные данные, то вам нужно пройти тест. Но если вы просто устанавливаете значения или возвращаете что-то без вычислений или логики, я не вижу преимущества в том, чтобы тесты охватывали эти методы, как если бы они были неправильными, вы сможете обнаружить проблему при визуальном осмотре или проблеме это языковой дефект.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...