Ошибка, возникающая с произвольной частотой во время тестов Capybara

#ruby-on-rails #ruby-on-rails-4 #capybara #minitest

#ruby-on-rails #ruby-on-rails-4 #capybara #minitest

Вопрос:

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

Мы используем Minitest и Capybara в качестве нашей платформы тестирования, с самого начала у нас были проблемы с некоторыми из наших спецификаций Capybara…

a) … передача и не передача на разных машинах (особенно в наших локальных системах и Travis CI)

б) … прохождение и не прохождение, казалось бы, произвольно во время разных запусков на наших локальных машинах

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

 require_relative '../../test_helper'

feature 'Review place' do
  before do
    create(:place, :reviewed)
  end

  scenario 'Do not show user edits in review index', :js do
    login
    visit '/places/1/edit'
    fill_in('place_name', with: 'USER CHANGE')
    click_on('Update Place')
    visit '/places/review_index'
    page.wont_have_content('USER CHANGE')
  end

  scenario 'Show guest edits in review index and review place', :js do
    visit '/places/1/edit'
    fill_in('place_name', with: 'GUEST CHANGE')
    validate_captcha
    click_on('Update Place')
    login
    visit '/places/review_index'
    page.must_have_content('SomeReviewedPlace')
    visit '/1/review_place'
    sleep(1)
    page.must_have_content('SomeReviewedPlace')
    page.must_have_content('GUEST CHANGE')
  end
end
  

и

 require_relative '../../test_helper'

feature 'Edit place' do
  before do
    create(:place, :reviewed)
  end

  scenario 'Do valid place update as user and show in index afterwards', :js do
    login
    visit '/places/1/edit'

    fill_in('place_name', with: 'Any place')
    fill_in('place_street', with: 'Schulze-Boysen-Str.')
    fill_in('place_house_number', with: '80')
    fill_in('place_postal_code', with: '10963')
    fill_in('place_city', with: 'Berlin')
    fill_in('place_email', with: 'schnipp@schnapp.com')
    fill_in('place_homepage', with: 'http://schnapp.com')
    fill_in('place_phone', with: '03081763253')
    click_on('Update Place')
    visit '/places'

    page.must_have_content('Any place')
    page.must_have_content('10963 Berlin')
  end

  scenario 'Do valid place update as guest and show in index afterwards as to be reviewed', :js do
    visit '/places/1/edit'
    fill_in('place_name', with: 'Some changes')
    validate_captcha
    click_on('Update Place')
    visit '/places'

    page.must_have_content('Some changes')
    page.must_have_css('.glyphicon-eye-open')
  end

  scenario 'Do valid place update as guest and do not show changes within other users session', :js do
    visit '/places/1/edit'
    fill_in('place_name', with: 'SomeOtherName')
    validate_captcha
    click_on('Update Place')

    Capybara.reset_sessions!
    visit '/places'
    page.wont_have_content('SomeOtherName')
    page.must_have_content('SomeReviewedPlace')
    page.wont_have_css('.glyphicon-eye-open')
  end
end
  

Оба теста произвольно завершаются ошибкой с

ActiveRecord::RecordNotFound: не удалось найти место с ‘id’=1

хотя такое место должно существовать из-за

 before do
  create(:place, :reviewed)
end
  

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

наилучшие пожелания и спасибо, Andi

Комментарии:

1. Вот что нужно попробовать: в следующий раз, когда произойдет сбой, обратите внимание на начальное значение, с которым выполнялись тесты, а затем повторно запустите тесты, передав --option rand:<thatseed> и посмотрите, не произойдет ли сбой снова. Кроме того, какой драйвер javascript вы используете? РЕДАКТИРОВАТЬ: повторный запуск с тем же исходным кодом гарантирует, что порядок выполнения тестов совпадает с неудачным запуском. если вы можете воспроизвести ее последовательно с одним и тем же исходным кодом, у вас может возникнуть некоторая нестабильность, основанная на том, какие тесты выполнялись до этого.

2. вы можете определить драйвер javascript, вставив puts page.driver.class в один из ваших тестов.

3. Эй, добавление --option rand:<thatseed>``does not work ( недопустимой опции: —option`

4. @jaydel: понял, rake test TESTOPTS="--seed=1261 работает для меня, спасибо за подсказку, действительно помогла мне найти ошибку!

5. прохладный. кстати, --option это мозговой пердеж. Вместо этого должно быть --order .

Ответ №1:

У вас есть пара проблем в ваших тестах

Во-первых, блок before запускается перед каждым сценарием, и при запуске второго сценария идентификатор созданного объекта, вероятно, равен 2 (если в предыдущем сценарии не было создано больше мест, тогда он был бы выше) и т.д. Чтобы решить эту проблему, вы должны сохранить создаваемый вами объект, а затем использовать его идентификатор для создания пути для посещения

 before do
  @place = create(:place, :reviewed)
end
  

затем, когда вам нужно посетить его

 visit("/places/#{@place.id}/edit") 
  

или с помощью помощников маршрута

 visit(edit_place_path(@place))  # preferred unless you're actually testing the text used for the url
  

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

 click_on('Update Place')
page.must_have_content('Place Updated') #whatever message is displayed
visit '/places'
  

Комментарии:

1. Спасибо, обе подсказки кажутся мне правдоподобными. К сожалению, они не решают проблему… Правильно ли, что ни один из коммитов в рамках функциональных тестов не сохраняется постоянно в БД? Другими словами: выполняется ли сброс тестовой базы данных перед тестированием нового сценария?

2. @А. Нейман При выполнении тестов, отличных от js, которые были бы правильными. Однако для тестов JS они должны быть зафиксированы, а затем использовать что-то вроде database_cleaner между сценариями для усечения или удаления созданных записей. Это необходимо, потому что в тестах JS приложение запускается в отдельном потоке с отдельным подключением к базе данных, поэтому, если записи фактически не зафиксированы, оно никогда их не увидит. Я не предлагал этого, потому что вы сказали, что иногда тесты проходят, чего не должно быть.

3. Мммм… Я тоже так думал. Но отладка целых файлов, содержащих спецификации выше, показывает, что изменения, появляющиеся в конце спецификации (они есть!), Не фиксируются и, следовательно, не видны в других тестах (чего я действительно хочу)!? У меня не установлен очиститель базы данных…

4. Теперь это работает, у меня была небольшая ошибка. Однако остается последний вопрос. Спасибо за вашу помощь. ваша подсказка была очень полезной!