如何在Capybara中重用代码

我在Rails的一个function测试中有一堆具有重复结构的代码。 我想通过重复使用结构来干掉我的规格。 有什么建议?

一个例子是:

feature "Search page" subject { page } it "should display results" # do something within "#A" do should have_content("James") end within "#B" do should have_content("October 2014") end # do something else # code with similar structure within "#A" do should have_content("Amy") end within "#B" do should have_content("May 2011") end end 

起初,我尝试在RSpec中定义一个自定义匹配器,但是当我withinwithin添加时,它似乎不起作用。 我的猜测是特定于Capybara,并且不能在RSpec中的自定义匹配器中使用。

为什么不将公共代码分解为模块中的辅助方法。 然后,您可以在spec_helper.rb文件中包含该模块

我通常将像user_login这样的公共代码放在spec / support文件夹中的文件中

spec_helper.rb

 #Load all files in spec/support Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} RSpec.configure do |config| #some config config.include LoginHelper #more config end 

规格/支持/ login_helper.rb

 module LoginHelper def do_login(username, password) visit root_path within("#LoginForm") do fill_in('username', :with => username) fill_in('password', :with => password) click_button('submit') end end end 

我不认为你within作为匹配器使用,因为匹配器将在shouldshould_not等之后使用。您可以通过编写模块并将其包含在spec_helper.rb中来将自定义非匹配器方法加载到您的规范中spec_helper.rb配置块,例如:

规格/支持/ my_macros.rb

 module MyMacros def within(tag, &block) # your code here end end 

投机/ spec_helper.rb

 require 'spec/support/my_macros' ... RSpec.configure do |config| config.include MyMacros ... end 

我正在使用Capybara + Cucumber进行端到端测试。 最后,我认为我已经完成了@hraynaud和@eirikir所建议的(定向地说) – 尽管细节因为我处于黄瓜环境中而有所不同。 所以,请考虑这不是一个完全不同的想法 – 但可能是稍微更完整的描述和讨论。 另外,请注意我的示例专注于测试结果 – 而不是导航和表单填写。 既然看起来你处于测试心态(假设你使用了should have_content ),我认为这可能会引起人们的兴趣。

一般来说,我的方法是:

  1. module中的validation帮助程序方法中包含Capybara测试。 包装的动机是(a)使我不必记住Capybara语法和(b)避免必须键入所有那些重复的测试语句。 此外,它最终使我的测试更清晰,更可读(至少对我而言)。
  2. 创建一个通用的validate方法,它接收(i)validation帮助器方法名称(作为符号)和(ii)一个项目数组,每个项目都将传递给validation帮助程序。 validate方法简单地遍历项目数组并调用validation帮助器方法(使用send方法),将每个项目与每次调用一起传递。
  3. 将帮助程序和通用validation方法附加到World( 在此处阅读有关World的更多信息),以便在我的Cucumber测试中可以使用它们。
  4. 享受测试快乐!

步骤1-3发生在名为form_validation_helpers.rb的文件中。

function/支持/ form_validation_helpers.rb

 module FormValidationHelpers ...more methods before # ============================================================================ # Tests that an element is on the page # ============================================================================ def is_present(element) expect(find(element)).to be_truthy end # ============================================================================ # Tests for the number of times an element appears on a page # ============================================================================ def number_of(options={}) page.should have_css(options[:element], count: options[:count]) end # ============================================================================ # Checks that a page has content # ============================================================================ def page_has_content(content) page.should have_content(content) end ...more methods after # ============================================================================ # The generic validation method # ============================================================================ def validate(validation, *items) items.each do |item| send(validation, item) end end end World(FormValidationHelpers) 

步骤4(从上面)发生在我的步骤文件中。

特征/ step_definitions / sample_steps.rb

 Then(/^she sees the organization events content$/) do validate :number_of, {element: 'ul#organization-tabs li.active', is: 1} validate :is_present, "ul#organization-tabs li#events-tab.active" validate :page_has_content, "A Sample Organization that Does Something Good", "We do all sorts of amazing things that you're sure to love." end 

正如您在validate :page_has_content示例中所看到的,我可以通过在validate调用中添加适当的参数来多次运行测试(因为validate方法在第一个参数之后接收所有内容到数组中)。

我喜欢在测试中使用非常具体的选择器 – 所以我可以肯定我正在测试正确的元素。 但是,当我开始更改我的视图文件时,我开始打破我的测试(坏),我必须返回并修复我的测试中的所有选择器 – 无论它们在哪里。 所以,我做了一堆选择器助手,并将它们连接到World,就像上面一样。

function/支持/ form_selectors_helpers.rb

 module FormSelectorsHelper ...more _selector methods before def event_summary_selector return 'input#event_summary[type="text"]' end ...more _selector methods after end World(FormSelectorsHelper) 

所以现在,我只有一个地方需要让我的选择器保持最新和准确。 用法如下(请注意,我可以传递validation助手方法所需的任何内容 – 字符串,方法,哈希,数组等)…

特征/ step_definitions / more_sample_steps.rb

 Then(/^she sees new event form$/) do validate :is_present, event_summary_selector, start_date_input_selector, start_time_input_selector, end_time_input_selector validate :is_absent, end_date_input_selector validate :is_unchecked, all_day_event_checkbox_selector, use_recur_rule_checkbox_selector validate :is_disabled, submit_button_selector validate :has_text, { element: modal_title_bar_selector, text: "Okay, let's create a new event!" } end 

回到你的问题,我想你最终会得到类似的东西:

 feature "Search page" subject { page } it "should display results" # do something validate :has_content_within, [a_selector, "James"], [b_selector, "October 2014"] # do something else validate :has_content_within, [a_selector, "Amy"], [b_selector, "May 2011"] end