Rspec, Cucumber: лучшая скорость очистки базы данных
Я хотел бы увеличить скорость моих тестов.
- Должен ли я использовать
use_transactional_fixtures
или пойти сdatabase_cleaner
драгоценный камень? - Какая стратегия database_cleaner является лучшей? Я заметил, что после миграции из
:truncation
в:transaction
мои более 800 примеров работают примерно в 4 раза быстрее! - Должен ли я выключить
use_transactional_fixtures
когда я использую database_cleaner:transaction
? - Правда ли, что лучшая стратегия для rack_test это
:transaction
? - Каковы лучшие практики для изменения стратегии на лету от
:transaction
в:truncation
при использовании селена или akephalos?
PS Mysql, Rails 3, Rspec2, Огурец
PPS Я знаю о spork и parallel_test и их использовании. Но они оффтоп. Например, Spork экономит около 15-20 секунд на весь запуск пакета, но меняется с :transaction
в :truncation
резко увеличить время работы с 3,5 до 13,5 минут (разница 10 минут).
4 ответа
1., 2. & 4., Вы должны использовать транзакции (либо с use_transactional_fixtures
или поддержка транзакций из самоцвета database_cleaner), если вы используете стандартный движок capybara, rack_test. Как вы заметили, использование транзакций значительно быстрее, чем использование стратегии усечения. Однако, когда запись в базу данных может проходить через разные потоки (как с селеном), транзакции не будут работать. Поэтому вам нужно использовать усечение (или заставить все проходить через один поток БД - другой вариант).
3. Да, вы должны выключить use_transactional_fixtures
при использовании самоцвета database_cleaner, поскольку самоцвет поддерживает транзакции. Если вам нужны только транзакции, просто используйте use_transactional_fixtures и никогда не загружайте гем database_cleaner.
5. Следующий код будет переключаться между :transaction
а также :truncation
на лету. (Протестировано это с помощью rspec, capybara, rails3.)
Особенности Это должно дать вам лучшее из обоих миров. Скорость rack_test
когда вам не нужно тестировать JavaScript и гибкость selenium
когда вы делаете.
Также этот код заботится о повторном заполнении начальных данных в тех случаях, когда это необходимо (этот метод предполагает, что вы используете seed.rb для загрузки своих начальных данных - в соответствии с действующим соглашением).
Добавьте следующий код в spec_helper.
config.use_transactional_fixtures = false
RSpec.configure do |config|
config.before(:suite) do
require "#{Rails.root}/db/seeds.rb"
end
config.before :each do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after(:each) do
if Capybara.current_driver == :rack_test
DatabaseCleaner.clean
else
DatabaseCleaner.clean
load "#{Rails.root}/db/seeds.rb"
end
end
end
Спасибо Джо Лисс за указание пути.
PS: как переключать драйверы на лету
Приведенное выше решение предполагает, что вы уже знаете, как переключать драйверы на лету. В случае, если некоторые, кто приезжает сюда, не делают, вот как:
Как и выше, давайте предположим, что вы обычно будете использовать драйвер по умолчанию для capybara rack_test, но вам нужно будет использовать селен для проверки некоторых вещей Ajaxy. Если вы хотите использовать драйвер селен, используйте :js => true
или же @javascript
для Rspec или огурца соответственно. Например:
Пример Rspec:
describe "something Ajaxy", :js => true do
Пример огурца:
@javascript
Scenario: do something Ajaxy
Использование фиксаций транзакций будет быстрее, поскольку СУБД не фиксирует изменения (и, следовательно, не происходит интенсивного ввода-вывода при перезагрузке базы данных между тестами), но, как вы знаете, не всегда будет работать.
Мы добились определенного успеха, используя базы данных SQLite в памяти в тестовой среде, поэтому тесты выполняются очень быстро, оставляя при этом транзакционные исправления отключенными. Эта опция также доступна для MySQL (используйте: опции, чтобы установить "ENGINE=MEMORY"), но я никогда не делал это лично, и если вы будете искать, вы найдете несколько тем о возможных предостережениях. Может стоит посмотреть. В зависимости от вашей методики тестирования может быть неприемлемо использовать другой механизм БД.
Я предлагаю вам включить транзакционные фикстуры и использовать гем DatabaseCleaner, чтобы выборочно отключать транзакционные фикстуры для каждой группы примеров. Не могу сказать, что пытался это сделать, но поскольку у вас не было ответов, я подумал, что что-то может вам помочь.
before(:all) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
before(:each) do
DatabaseCleaner.start
end
after(:each) do
DatabaseCleaner.clean
end
Если бы это был я, я бы выделил это в помощник и вызвал бы его как однострочный макрос из каждой группы примеров, для которой необходимо отключить фиксацию транзакций.
Похоже, что действительно должен быть лучший путь... удачи.
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
Это из поста Авди Гримм о очистителе базы данных и Rspec. Пошаговый анализ кода есть в статье.
Вы использовали Spork? Это значительно увеличивает скорость.