一个简单的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/



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