頁面流程測試


如果想測試各個控制器、頁面之間的流程互動,可以繼承ActionDispatcher::IntegrationTest,它繼承自ActiveSupport::TestCase,新增了一些方法,可測試跨動作或控制器的流程,由於流程實際是在測試應用程式的行為,因此屬於整合測試的範疇。

可以使用rails產生整合測試的骨架,例如:

~gossip\$ gossip\$ rails generate integration_test user_flows
      invoke  test_unit
      create    test/integration/user_flows_test.rb


接著編輯test/integration/user_flows_test.rb,以下是個針對 Cookie 中範例,使用者從首頁被轉發至登入頁而後登入成功的測試:
  • user_flows_test.rb
require 'test_helper'

class UserFlowsTest < ActionDispatch::IntegrationTest
  fixtures :all

  test "forward user to login successfully" do
    get "/tests/index"
    assert_redirected_to :controller => "tests", :action => "login"

    follow_redirect!
    assert_equal "/tests/login", path

    post "/tests/login", {user: "caterpillar", passwd: "123456"}
    assert_response :success
    assert_equal "caterpillar", assigns(:user)
    assert_select "title", "Welcome"
  end
end

如果要測試多個使用者以上的行為,測試的程式碼會變得冗長且重複,此時可以嘗試利用Ruby的特性自訂DSL,讓測試程式的語意更為清晰。例如:

  • user_flows_test.rb
require 'test_helper'

class UserFlowsTest < ActionDispatch::IntegrationTest
  fixtures :all

  test "forward user to login" do
    visitor1 = forward(:visitor1)
    visitor1.login("caterpillar", "123456")
    visitor1.assert_select "title", "Welcome"

    visitor2 = forward(:visitor2)
    visitor2.login("someone", "123456")
    visitor2.assert_select "title", "Login"
  end
  
  module UserDsl
    def login(user, passwd)
      post "/tests/login", {user: user, passwd: passwd}
      if redirect?
        follow_redirect!
      end
    end
  end

  def forward(user)
    open_session user do |sess| 
      sess.extend(UserDsl)
      sess.get "/tests/index"
      sess.assert_redirected_to :controller => "tests", :action => "login"
      
      sess.follow_redirect!
      sess.assert_equal "/tests/login", sess.path
    end
  end
end

其它整合測試的例子,可以參考 ActionDispatcher::IntegrationTest 文件,或者是 A Guide to Testing Rails Applications 中的 IntegrationTest