一個簡單的Cucumber+Capybara的BDD開發例子

Cucumber是一個用來做BDD( Behavior Driven Design)的工具。你可以用自己的語言來寫場景(scenarios)和定義(definitions).

Capybara可以用來模擬用戶對瀏覽器(browser)的訪問。


下載和配置

下載cucumber到本地:  

 $gem install cucumber

創建好你的rails項目以後, 編輯 Gemfile 加上Cucumber:

group :development, :test do
  gem "rspec-rails", ">= 2.0.1"
  gem 'cucumber-rails'
  gem 'database_cleaner'
end

創建你的測試

在你的Rails項目裏, Cucumber測試在 features文件夾下面的 .feature後綴文件裏。 可參考Cucumber目錄結構和執行過程

你可以創建一個 contact.feature 文件寫上一些場景(scenario):


Feature: Contact me
    In order to get in touch
    A visitor
    Should send me a message by contact form
 
    Scenario: Sends a contact message
        Given I am on the contact page
        And I fill in "contact visitor name" with "John"
        And I fill in "contact visitor email" with "[email protected]"
        And I fill in "contact subject" with "Hello"
        And I fill in "contact message" with "Great post!"
        When I press "Send message"
        Then page should have notice message "Your message was successfully delivered."

* 注意縮進  ( 注: 是否應該是縮進2格?  上面代碼是縮進4格的)

場景(scenario)是由很多步驟(steps)組成的。

一個步驟(step)是一個驗證(validation)或者一個更簡單的測試(simple test).

開始運行cucumber命令:    

$ bundle exec cucumber

將得到警告說步驟沒有定義:

cucumber_test$ bundle exec cucumber
Using the default profile...
Feature: Contact me

(....)

You can implement step definitions for undefined steps with these snippets:

Given /^I am on the contact page$/ do
  pending # express the regexp above with the code you wish you had
end

Given /^I fill in "(.*?)" with "(.*?)"$/ do |arg1, arg2|
  pending # express the regexp above with the code you wish you had
end

When /^I press "(.*?)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end

Then /^page should have notice message "(.*?)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end

這裏要用capybara模擬瀏覽器的訪問。

在 features/step_definitions/  文件夾創建 navigation_steps.rb

require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))

Given /^I am on (.+)$/ do |page_name|
  visit path_to(page_name)
end

When /^I go to (.+)$/ do |page_name|
  visit path_to(page_name)
end

When /^I press "([^\"]*)"$/ do |button|
  click_button(button)
end

When /^I click "([^\"]*)"$/ do |link|
  click_link(link)
end

When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |field, value|
  fill_in(field.gsub(' ', '_'), :with => value)
end

When /^I fill in "([^\"]*)" for "([^\"]*)"$/ do |value, field|
  fill_in(field.gsub(' ', '_'), :with => value)
end

When /^I fill in the following:$/ do |fields|
  fields.rows_hash.each do |name, value|
    When %{I fill in "#{name}" with "#{value}"}
  end
end

When /^I select "([^\"]*)" from "([^\"]*)"$/ do |value, field|
  select(value, :from => field)
end

When /^I check "([^\"]*)"$/ do |field|
  check(field)
end

When /^I uncheck "([^\"]*)"$/ do |field|
  uncheck(field)
end

When /^I choose "([^\"]*)"$/ do |field|
  choose(field)
end

Then /^I should see "([^\"]*)"$/ do |text|
  page.should have_content(text)
end

Then /^I should see \/([^\/]*)\/$/ do |regexp|
  regexp = Regexp.new(regexp)
  page.should have_content(regexp)
end

Then /^I should not see "([^\"]*)"$/ do |text|
  page.should_not have_content(text)
end

Then /^I should not see \/([^\/]*)\/$/ do |regexp|
  regexp = Regexp.new(regexp)
  page.should_not have_content(regexp)
end

Then /^the "([^\"]*)" field should contain "([^\"]*)"$/ do |field, value|
  find_field(field).value.should =~ /#{value}/
end

Then /^the "([^\"]*)" field should not contain "([^\"]*)"$/ do |field, value|
  find_field(field).value.should_not =~ /#{value}/
end

Then /^the "([^\"]*)" checkbox should be checked$/ do |label|
  find_field(label).should be_checked
end

Then /^the "([^\"]*)" checkbox should not be checked$/ do |label|
  find_field(label).should_not be_checked
end

Then /^I should be on (.+)$/ do |page_name|
  current_path.should == path_to(page_name)
end

Then /^page should have (.+) message "([^\"]*)"$/ do |type, text|
  page.has_css?("p.#{type}", :text => text, :visible => true)
end

在 features/support/ 文件夾 增加一個 support文件  paths.rb

module NavigationHelpers
  def path_to(page_name)
    case page_name
 
    when /the home\s?page/
      '/'
    else
      begin
        page_name =~ /the (.*) page/
        path_components = $1.split(/\s+/)
        self.send(path_components.push('path').join('_').to_sym)
      rescue Object => e
        raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
          "Now, go and add a mapping in #{__FILE__}"
      end
    end
  end
end

World(NavigationHelpers)

再次跑一邊測試:

$ bundle exec cucumber

現在,你可以做代碼方面的事了。  寫 models,  controllers, views, routes.

這兒是我的例子, 步驟定義的是簡單的瀏覽(navigation), 但你可以寫更復雜的測試, 要讓場景簡單,比如 When I fill contact form可以定義成這樣:

When /^I fill contact form$/ do
  visit contact_form_path
  fill_in('contact_visitor_name', :with => "John")
  fill_in('contact_visitor_email', :with => "[email protected]")
  fill_in('contact_subject', :with => "Hello")
  fill_in('contact_message', :with => "Great post! Bye.")
  click_button("Send message")
end

原文: http://loudcoding.com/posts/quick-tutorial-starting-with-cucumber-and-capybara-bdd-on-rails-project/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章