Тесты, просто чудесная вещь, но как и многое чудесное имеет свои недостатки. Главный из них – они очень долго выполняются. Сегодня мы рассмотрим два инструмента для улучшения ситуации.

Spork

Spork – это инструмент, который позволяет не перегружать тестовое окружение (например, сам Rails, rspec и прочие тестовые библиотеки, которые вы используете), всякий раз, как прогоняется тест. Вместо этого вы запускаете spork (для rspec или unit test) или spork cuc (для cucumber), дожидаетесь, пока он подгрузит окружение, и после этого запускаете ваш rspec или cucumber с ключём --drb. И они начинают гонять тесты, минуя стадию подгрузки окружения! С настройкой, вы справитесь очень легко.

Да, для Rails 3 вам понадобится rc-версия spork (на данный момент, 0.9.0.rc2), а cucumber + autotest не работают с spork’ом хотя кто-то утверждает, что всё в порядке.

Parralel_tests

parallel_tests – инструмент, позволяющий распарралелить выполнение тестов (test unit), спек (rspec) или фич (cucumber). Надо понимать, что он запускает параллельно разные файлы, но не отдельные тесты внутри одного файла. Поэтому ускорить выполнение одного большого спека вам не удастся.

Всё, что вам нужно делать, это создать БД как сказано в README, а также после каждой миграции делать rake parralel:prepare.

Запускать можно как с параметрами по-умолчанию rake parallel:spec (в этом случае количество процессов определится автоматически по числу ядер), так и указав количество процессов и путь: rake parallel:spec[4,models].

Я провёл несколько испытаний. Rspec:

$ date && rake spec:controllers && date
Сбт Ноя 13 14:53:38 MSK 2010
Finished in 58.36 seconds
350 examples, 0 failures
Сбт Ноя 13 14:55:33 MSK 2010

Итого, Rspec утверждает, что справился за 58.36 секунд, а по выводу команды date видно, что потребовалось 115. Т.е. ещё 57 секунд (которые, кстати, мог бы сэкономить spork) потребовалось на загрузку окружений. Кстати, на подгрузку окружения для команды rspec spec/contollers или для команды bundle exec rspec spec/contollers тратится около 30 секунд (на bundle на пару секунд дольше).

Посмотрим, на parallel с параметрами по-умолчанию:

$ date && rake rake parallel:spec[controllers] && date
Сбт Ноя 13 14:55:33 MSK 2010
2 processes for 16 specs, ~ 8 specs per process
Finished in 10.39 seconds
184 examples, 0 failures
Finished in 51.1 seconds
166 examples, 0 failures
Results:
166 examples, 0 failures
184 examples, 0 failures
Took 89.216297137 seconds
Сбт Ноя 13 14:57:19 MSK 2010

В первый раз я вывел весь лог, чтобы было понятно, как он выглядит, далее будет короткая выдержка.
Итого: 89.216297137 секунд по словам parralel_test и 106.0 фактических секунд (сэкономлено ~9 секунд). 89 сек – странная цифра, т.к. реальное время выполнения – максимальное из всех процессов, т.е. 51.1, что соответствует экономии в 9 секунд.

$ date && rake rake parallel:spec[4,controllers] && date
Сбт Ноя 13 14:57:19 MSK 2010
4 processes for 16 specs, ~ 4 specs per process
Took 130.743829138 seconds
Сбт Ноя 13 14:59:47 MSK 2010

А вот попытка выполнить на 4_ёх процессах (при реальных 2_ух ядрах) только ухудшила ситуацию: 148.0 – реальных секунд и 130.743829138 заявленных.

Тесты для cucumber:

$ rake cucumber
Сбт Ноя 13 15:26:32 MSK 2010
5m38.088s
Сбт Ноя 13 15:33:09 MSK 2010

Т.е. реальных 6 минут 37 секунд, заявленных 5 минут 38 секунд. Т.е., как и прежде – около минуты на подгрузку окружения.

$ rake parallel:features
Сбт Ноя 13 15:37:28 MSK 2010
Took 268.90437579 seconds
Сбт Ноя 13 15:41:54 MSK 2010

Итого – почти 4 с половиной минуты заявленны, а реальных 4 минуты 50 секунд. Т.е. выигрыш по сравнению с непараллельными тестами 1 минута 47 секунд. Кстати, при прогоне тестов с selenium реально запускаются два сервера и две копии браузера. При этом два сервера могут конфликтовать.

$ rake parallel:features[4]
Сбт Ноя 13 15:41:58 MSK 2010
Took 323.654938436 seconds
Сбт Ноя 13 15:47:39 MSK 2010

Итого на 5:20 заявленных, 5:41 реальных, что всё равно лучше, чем вообще без распарралеливания, но сильно хуже 2 процессов.

К сожалению, spork и parralel_test не работают вместе :(

Итого:

  1. Использование rake spec вместо rspec scec/ или bundle exec rspec увеличивает время выполнения теста ~ на 30 секунд. Кстати, parralel_test для Rspec запускаются командой parallel_spec или bundle exec parallel_spec (т.е. +30 секунд экономии по сравнению с rake).
  2. Если используете parralel_test, то оптимальным числом процессов является значение по-умолчанию (т.е. число ядер)
  3. При выполнении одного теста, т.е. в рядовой работе, parralel_test не даст выигрыша вообще, а spork сэкономит по 30 секунд на прогон.
  4. parralel_test – отличная вещь при прогоне всех тестов перед выгрузкой коммита в общий репозиторий.

P.S. Rails 3 + Ruby 1.9.2 + rspec 2.0.1 + cucumber 0.9.3

1 комментарий [написать ещё один]

[IMG]

Евгений Золотарёв, 13 ноября 2010 года

Не хватает сводной таблицы.