简体   繁体   English

如何在Rails中进行DRY测试并仍然使用Capybara和Warden? (使用最小测试)

[英]How can I make tests DRY in Rails and still use Capybara and Warden? (using minitest)

My intention is to create a few tests for the same form, and in these tests I need Capybara to fill the form completely. 我的意图是为同一表格创建一些测试,在这些测试中,我需要Capybara才能完全填写表格。 Still, I wanted to avoid rewriting the code for filling the form. 尽管如此,我还是希望避免重写用于填写表格的代码。

I'm not using RSPEC! 我没有使用RSPEC! I'm using minitest. 我正在使用minitest。

The problem I'm facing is that the Capybara method visit and the Warden helper method login_as are not accessible from my CapybaraHelper module. 我现在面临的问题是,水豚方法visit和监狱长的辅助方法login_as不能在我访问CapybaraHelper模块。

I've seen this question, so I created my module in the test/support folder, but the methods I mentioned still are not accessible. 我已经看到了这个问题,所以我在test/support文件夹中创建了我的模块,但是我提到的方法仍然无法访问。 How to reuse code in Capybara 如何在Capybara中重用代码

I've seen this question, but the code I want to reuse doesn't seem to fit well in the setup method nor in the teardown method. 我已经看到了这个问题,但是我想重用的代码似乎不太适合setup方法或teardown方法。 Rails: Premake a model instance for your unit tests (for DRY purposes)? Rails:为您的单元测试预先制作一个模型实例(用于DRY)?

I've also seen posts saying this module should be inside test_helper.rb , but as I add more modules to this file it will get messy. 我也看到过帖子说该模块应该在test_helper.rb ,但是当我向该文件添加更多模块时,它会变得凌乱。

So now I'm wondering what I'm doing wrong. 所以现在我想知道我在做什么错。 I've tried adding the following lines to CapybaraHelper but it didn't help. 我尝试CapybaraHelper添加到CapybaraHelper但没有帮助。 It actually raised the error NoMethodError: undefined method setup' for CapybaraHelper:Module`. 实际上,它为NoMethodError: undefined method引发了错误NoMethodError: undefined method setup。

include Devise::Test::ControllerHelpers
include Warden::Test::Helpers

Is it the right way to reuse code in tests? 在测试中重用代码是否正确? Am I missing something that should be included in my helper module? 我是否缺少帮助程序模块中应包含的内容? All those methods work perfectly in the test controller that is using CapybaraHelper:Module . 所有这些方法都可以在使用CapybaraHelper:Module的测试控制器中完美地工作。

Here is the error message: 这是错误消息:

NoMethodError: undefined method `login_as' for CapybaraHelper:Module

And here is an error message from another test using CapybaraHelper:Module . 这是来自另一个使用CapybaraHelper:Module测试的错误消息。

NoMethodError: undefined method `visit' for CapybaraHelper:Module

Here's my test: 这是我的测试:

require 'test_helper'

class TravelsControllerTest < ActionController::TestCase
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  Warden.test_mode!

  test 'should accept correct fields' do
    CapybaraHelper.login
    result = CapybaraHelper.access_and_fill_travel_page
    assert_equal "/travels/success/#{Travel.last.uuid}", result[:final_path]
  end

end

And here's the helper I created in test/support/capybara/capybara_helper.rb to avoid code duplication: 这是我在test/support/capybara/capybara_helper.rb创建的帮助程序,以避免代码重复:

require 'test_helper'
require 'capybara/rails'
require 'capybara/poltergeist'

module CapybaraHelper
  def self.access_and_fill_travel_page options = {}
    options.symbolize_keys!
    set_js_driver
    visit(Rails.application.routes.url_helpers.root_path)
    initial_path = current_path
    #Fields
    fill_in('origin', with: options[:origin] || 'Guarulhos')
    fill_autocomplete('origin', with: options[:origin] || 'Guarulhos')
    fill_in('destination', with: options[:destination] || 'Seul')
    fill_autocomplete('destination', with: options[:destination] || 'Seul')
    fill_in('date_from', with: options[:date_from] || Date.today+10)
    fill_in('date_to', with: options[:date_to] || Date.today+26)
    fill_in('adults', with: options[:adults] || 1)
    fill_in('children', with: options[:children] || 0)
    fill_in('babies', with: options[:babies] || 0)
    find('#travel-submit').click()
    final_path = current_path
    return {initial_path: initial_path, final_path: final_path}
  end

  def self.fill_autocomplete(field, options = {})
    page.execute_script %Q{ el = $('input[name=#{field}]').get(0) }
    page.execute_script %Q{ $(el).trigger('focus') }
    page.execute_script %Q{ $(el).trigger('keydown') }
    page.all('.ui-menu-item', minimum: 1)
    page.execute_script %Q{ item = $('.ui-menu-item').get(0) }
    page.execute_script %Q{ $(item).trigger('mouseenter').click() }
  end

  def self.set_js_driver
    Capybara.javascript_driver = :poltergeist
    Capybara.current_driver = Capybara.javascript_driver
  end

  def self.login
    user = FactoryGirl.create(:user)
    login_as(user, :scope => :user)
  end

end

You should use ActionDispatch::IntegrationTest and not ActionController::TestCase as the parent class for tests using capybara. 您应该将ActionDispatch::IntegrationTest而不是ActionController::TestCase用作使用水豚进行测试的父类。 ActionController::TestCase mocks out the request phase and large parts of Rails. ActionController::TestCase模拟了请求阶段和Rails的大部分内容。 It is depreciated in Rails 5. 在Rails 5中已贬值。

Instead of calling methods on your test helper module you should mix them into your test classes. 不应在测试帮助程序模块上调用方法,而应将它们混合到测试类中。

class TravelsIntegrationTest < ActionDispatch::IntegrationTest
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  include CapybaraHelper 
  Warden.test_mode!

  test 'should accept correct fields' do
    login
    # ...
  end
end

module CapybaraHelper
  def login(user = FactoryGirl.create(:user))
    login_as(user, scope: :user)
  end
end

Apart from that you are lacking in code organization - setup steps like setting Warden.test_mode! 除此之外,您还缺乏代码组织功能-设置Warden.test_mode!类的设置Warden.test_mode! should be done in your test_helper.rb not repeated across your tests. 应该在test_helper.rb完成,不要在所有测试中重复进行。 Don't throw all your step definitions into a single file either. 也不要将所有步骤定义都放入一个文件中。 You can place them in /test/support/ for example. 例如,您可以将它们放在/test/support/中。

module SessionHelper
  def login(user = FactoryGirl.create(:user))
    login_as(user, :scope => :user)
  end
end

module TravelHelper
  def access_and_fill_travel_page
    # ...
  end
end

And if you really want to keep it dry use inheritance to setup your test classes: 如果您真的想保持干燥,请使用继承来设置测试类:

class BaseIntegrationTest < ActionDispatch::IntegrationTest
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  include SessionHelper 
end

class TravelsIntegrationTest < BaseIntegrationTest
  test 'should accept correct fields' do
    login
    # ...
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Minitest的Rails,如何设置RuboCop在每次使用rake运行测试时自动运行? - With Rails using Minitest, how can I set up RuboCop to run automatically each time tests are run with rake? 如何在Rails中使这些RSpec测试更加干燥 - How to make these RSpec tests more DRY in Rails 我怎样才能让我的 controller 更干燥——我想在 controller 中使用助手——Rails 3 - How can I make my controller more DRY — I'd like to use helpers within controller — Rails 3 Rails:如何在我的Capybara集成测试中测试秒表? - Rails: how can I test a stopwatch in my Capybara integration tests? 如何在我的rails minitest中使用模拟? - How can I use mock in my rails minitest? 使用Rails 5和minitest,如何访问在测试中创建的记录? - Using Rails 5 and minitest, how can I access a record that was created in the test? rails 3:我该如何干燥? - rails 3: How can I DRY this? 如何使用devise的“ warden”对与使用devise的rails应用程序位于同一堆栈中的机架应用程序进行身份验证? - How can I use devise's “warden” to authenticate a rack app in the same stack as the rails app that uses devise? 使用minitest / capybara设置一次登录以运行Rails测试 - Setting up one time login with minitest/capybara for running rails tests 如何使其干燥? - How can I make it DRY?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM