天天看点

Rails 集成测试写法的变化过程 Rails测试方法合集

在[url]http://giantrobots.thoughtbot.com[/url]逛的时候看到的,小夜觉得有些东西还是能说明问题的,就抄回来了。

[size=large]Productivity and happiness.[/size]这是Ruby和Rails升起的原因,也是integration testing能够持续变化的原因。当然,原文作者客气的说,这只是个人理解并没有科学证据。

[size=large]2006[/size]

使用如下方法[quote]get, post, follow_redirect!, xml_http_request, status, path, and open_session[/quote]通过assert_equal来验证。通常写法如下:

class ExampleTest < ActionController::IntegrationTest
  def test_login
    get "/login"
    assert_equal 200, status

    post "/login",
      :username => people(:jamis).username,
      :password => people(:jamis).password
    follow_redirect!

    assert_equal 200, status
    assert_equal "/home", path
  end
end
           

[size=large]2007[/size]

[size=large][color=red]RSpec[/color][/size]引入所谓行为驱动,就是故事模式如下:

Scenario "Root user" do
  Given "a user named", "admin"
  And "a company named", "Company1"
  And "a company named", "Company2"

  And "the user has the role", "root" do |role|
    @user.update_attribute :role, role
  end
  And "logged in as", "admin"

  When "visiting", "/"

  Then "viewer should see", "main/root_home"
  And  "page should show company named", "Company1" do |name|
    response.should have_text(/#{name}/)
  end
  And  "page should show company named", "Company2"
end
           

[size=large][color=red]Webrat[/color][/size]在这个时候模拟浏览器行为用于测试网页。 [color=red]DSL[/color]通过[quote]click_link, fill_in, and click_button[/quote]

[color=red]Webrat[/color]可以和 配合使用[color=red]Nokogiri[/color]测试网页,使用XPath 和 CSS selectors来验证HTML的返回。

通常这样写:

def test_sign_up
  visits "/"
  clicks_link "Sign up"
  fills_in "Email", :with => "[email protected]"
  select "Free account"
  clicks_button "Register"
  ...
end
           

[size=large]

2008[/size]

[size=large][color=red]Merb[/color][/size]推荐使用request方法。而这也比dispatch_to更容易。通常会用到[quote] be_successful and redirect_to[/quote]

这时[size=large][color=red]Cucumber[/color][/size]取代讲故事的Story Runner模式。如下:

[size=large]2009

[/size]

Integration testing 成为主流

[color=red][size=large]Rack::Test[/size][/color]通过给测试框架提供一个公用的接口来和Rack应用交互。

[quote]Rack::Test pays homage to the frameworks before it, using methods that match the HTTP verbs: get, post, put, and delete, head) and adding request (Merb) and follow_redirect! (Rails). It also handles HTTP authentication and stores requests and responses in last_request and last_response.[/quote]

示例如下:

class HelloWorldTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    [color=red]Sinatra[/color]::Application
  end

  def test_it_says_hello_world
    get '/'
    assert last_response.ok?
    assert_equal 'Hello World', last_response.body
  end

  def test_it_says_hello_to_a_person
    get '/', :name => 'Simon'
    assert last_response.body.include?('Simon')
  end
end
           

[color=red]Cucumber and Webrat [/color]也得到发展

Feature "A Tomatoist does a pomodoro" do
  Story <<-eos
  In order to perform a focused unit of work
  As a Tomatoist
  I want to start a pomodoro
  eos

  Scenario "Starting a pomodoro" do
    When "I go to the home page" do
      executes { visit '/' }

      Then "I should be sent to a new session" do
        current_url.should =~ /\/\w{3,}/
      end

      And "I should see an unstarted timer" do
        response.should have_tag('#timer .countdown_row','00:00')
      end

      When "I click the pomodoro button" do
        executes do
          @session_url = current_url
          click_button 'Pomodoro'
        end

        Then "I should be on my session's page" do
          current_url.should == @session_url
        end

        And "my timer history should show the current pomdoro" do
          response.should have_tag('#history ul li', /Pomodoro/, 1)
        end
      end
    end
  end
end
           

[size=large][color=red]Coulda[/color][/size]同样使用定义语言通过[color=red]Webrat[/color]或者其他库来模拟浏览器行为如下:

[color=red]Given[/color]同样

class StackBehavior < Given::TestCase
  Invariant { expect(@stack.depth) >= 0 }
  Invariant { expect(@stack.empty?) == (@stack.depth == 0) }

  def empty_stack
    @stack = Stack.new
  end

  Given(:empty_stack) do
    Then { expect(@stack.depth) == 0 }

    When { @stack.push(:an_item) }
    Then { expect(@stack.depth) == 1 }
    Then { expect(@stack.top) == :an_item }

    When { @stack.pop }
    FailsWith(Stack::UsageError)
    Then { expect(exception.message) =~ /empty/ }
  end
end
           

[quote]I write about 50 lines of horrible hacks. It brings the Given/When/Then DSL to Test::Unit. It relies on Webrat and Rack::Test to simulate the browser and theoretically work for all Rack apps (only tested on Sinatra). I keep the nesting totally flat, as is my style. It looks like this:[/quote]

Feature 'Shorten URL' do
  Given 'I am on the homepage' do
    visit '/'
  end

  When 'I submit http://example.com' do
    fill_in      'url', :with => 'http://example.com'
    click_button 'shorten'
  end

  Then 'I should see a short link' do
    assert_have_selector 'a#short'
  end

  When 'I follow the short link' do
    click_link 'short'
  end

  Then 'I should be on http://example.com' do
    assert_equal 'http://example.com', current_url
  end
end
           

原文还有一些解释,没太注意,然而,从这样一个Rails的测试进化过程,还是能够看到一些东西。