Rails 3.0.7 -> Как заставить ваши тесты работать быстрее? - PullRequest
15 голосов
/ 22 мая 2011

Я использую mysql, database_cleaner, Rspec и т. Д. На данный момент у меня около 518 тестов, и они занимают 88 секунд. Для меня это неприемлемо, так как разработка моего приложения только начинается.

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

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

Я думаю, что database_cleaner замедляет их, но я не знаю, как тестировать запросы и прочее без него.

Использование sqlite3 с опцией ": memory:", кажется, сбрасывает только около 10 секунд (что-то неутешительный результат ...)

Что я могу сделать, чтобы действительно ускорить мои тесты?

Ответы [ 6 ]

17 голосов
/ 22 мая 2011

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

  • Использовать spork - Spork выполнит всю загрузку и требуемую среду один раз, сохранит ее в памяти и перезагрузит только ваши тесты. Это может быть очень полезно для быстрого запуска тестов.
  • Будьте умны в том, как вы тестируете - Лично я работаю над разработкой тестов, запуском полного набора тестов, чтобы увидеть, что не получается, а затем запускаю только новые / неудачные тесты, пока я не получу эти зеленые. , Наконец, когда я все закончил, я запустил пакет в последний раз, чтобы посмотреть, регрессировал ли я еще.
  • Очистите свой Gemfile - Большая часть времени загрузки Rails тратится в потребностях, и если у вас есть гемы, которые вы больше не используете, вы добавляете время загрузки без какой-либо выгоды. Уберите все, что вы не используете, и рассмотрите возможность размещения вещей, которые используются только в одном или двух местах в именованной группе, чтобы вы могли потребовать их вручную во время выполнения (будьте осторожны - вы торгуете начальной скоростью загрузки для выполнения запроса, что отлично подходит для Dev, но дрянной для производства)
  • Будьте умны в отношении того, что заглушки и макеты - Если вы действительно проводите модульные тесты, например, вам следует избегать касания базы данных вообще или, по крайней мере, для тестов вашего контроллера. Подумайте о том, какова ответственность класса на самом деле. Контроллер не несет ответственности за сохранение записей, он отвечает за указание моделям сохранять записи. Даже модели не несут ответственности за сохранение данных в базах данных, они отвечают за указание ActiveRecord.
  • Если вы хорошо ошарашиваете, не включайте Rails . Вам понадобится отключить почти все функциональные возможности ActiveRecord в своих тестах, но если вы сможете это сделать, вы увидите массовое сокращение вашего времени тестирования (возможно, более чем на порядок).
5 голосов
/ 26 мая 2011

Райан Бруннер дал много хороших советов.Все, что он сказал, в целом верно, но ко мне это не относится.

Я не упомянул Factory Girl, потому что не думал об этом упоминать (не спрашивай).Это оказалось очень важной деталью, потому что она отвечала за такие медленные тесты.

Просто полностью удалив Factory girl из тестов моего контроллера (я использовал Factory.build), мне удалось их получитьс 50 секунд до примерно 5.

Причина в том, что Factory.build вызывает Factory.create для ассоциаций, что приводит к попаданию в базу данных ... так что если у вас много ассоциаций, это займет некоторое времясоздать новый объект модели.Но более того, в моем случае это составляло только 30-35% накладных расходов.Factory_girl тратила 65-70% своего времени на работу без базы данных.Я понятия не имею, почему, но после того, как все вызовы будут равны Factory.build, на создание моих объектов уйдет совсем немного времени.Переход с базового MyClass.new оказался НАМНОГО быстрее.

Весь мой набор тестов теперь занимает чуть менее 30 секунд вместо 90 секунд.Это увеличение скорости на 300% в целом за счет внесения этих изменений ... но когда дело дошло до испытаний контроллера, я получил увеличение скорости на 2000% - и я уже заглох!Все это было связано с Factory.build!Вот откуда большинство преимуществ.

Конечно, я вернулся к своим моделям и использовал Factory.build или просто MyClass.new везде, где мог.

Я также добавил :default_strategy => :build в factories.rb тоже, когда я мог, чтобы Фабричная Девочка не попала в базу данных.Если вы спросите меня, это должно быть по умолчанию, так как в результате этого изменения произошел только 1 тест, но мне удалось получить 10 полных секунд из моих модельных тестов только за счет этого изменения.

Если выЕсли у вас возникли проблемы, как у меня, выполните следующие действия, и вы заметите улучшение скорости в 2-3 раза с небольшим недостатком.

3 голосов
/ 22 мая 2011

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

http://makandra.com/notes/950-speed-up-rspec-by-deferring-garbage-collection

В статье упоминается улучшение на 15%, но в моих тестах я вижу около 25% с Ruby 1.9.2, Rails 3.0.x и RSpec 2.0.

Кроме того, если вы не используете автотест, это может помочь, поэтому вы запускаете тесты только для кода, который изменился.

Наконец, попробуйте использовать опцию RSpec "--profile", чтобы определить 10 самых медленных примеров и посмотреть, сможете ли вы оптимизировать производительность худших нарушителей; В одном из моих проектов оказалось, что только 3 из моих тестов удвоили время выполнения моих тестов на 150 тестов, поэтому я «исправил» их, и это вернуло весь набор тестов к приемлемой шкале времени.

0 голосов
/ 22 мая 2011

Посмотрите на параллельное тестирование с Hydra:

http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/

Смотрите также здесь:

http://www.adomokos.com/2011/04/running-rails-rspec-tests-without-rails.html

0 голосов
/ 22 мая 2011

Я думаю, что если вы включите use_transactional_fixtures в RSpec, вам вообще не нужно будет использовать database_cleaner.

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

0 голосов
/ 22 мая 2011

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

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