A test for invalid submission

在沒有完全支持測試的強大 Web 框架出現之前,都必須透過手動來測試表單,你必須要測試無效跟有效的資訊,每次修改時又要重複幾遍這樣的動作。

Rails 可以編寫測試,自動測試表單,接下來我們要寫一個測試,測試當表單提交無效的資訊錯時,會不會正常反映出相關資訊。

現在建立一個整合測試(integration test)的檔案,用來測試註冊,名稱為 users_signup ,慣例使用 resource 的複數名稱:

$ rails generate integration_test users_signup
      invoke  test_unit
      create    test/integration/users_signup_test.rb

之後會使用這個檔案,繼續編寫有效的註冊測試。

這個測試的主要目的是,當提交無效資訊並點擊送出按鈕之後,並不會建立新使用者。(對錯誤訊息的測試留在練習題)方法是檢查使用者的數量。在測試中會使用 count 方法,這個方法在 Active Record class 中(包括 User class)都能應用:

$ rails console
> User.count
=> 0

因為之前把資料庫 reset 了,所以現在使用者為 0 個。我們要使用 assert_select 檢查相關頁面的 HTML 元素(這個方法只能測試以後不會修改的元素)。

首先我們會先用 get 方法讀取註冊頁面:

get signup_path

為了測試表單提交後的狀態,我們要向 users_path 發出 POST 請求:

assert_no_difference 'User.count' do
  post users_path, user: { name:  "",
                           email: "user@invalid",
                           password:              "foo",
                           password_confirmation: "bar" }
end

這裡使用 create action 傳給 User.newparams[:user] hash。把 post 方法放在 assert_no_difference 方法的 block 裡面,並把 assert_no_difference 方法的參數,設定為 User.count 字串。這段程式碼被執行時,會去比較 User.countassert_no_difference block 中,前後的值的狀態(before and after of the contents of the assert_no_difference block)。

這段程式碼等於會先計算使用者的數量,然後用 POST 發送資料,最後檢查使用的數量沒變:

before_count = User.count
post users_path, ...
after_count  = User.count
assert_equal before_count, after_count

上述兩種方式都是同樣的作用,但使用 assert_no_defference 會更簡潔清楚,也是 Ruby 慣用的語法。

上述用到的 getpost 其實在技術上比較無關緊要,實際上也不是一定要先 get 到註冊頁面才能 post 資料。原作者習慣包含這兩個步驟,看起來會更清楚,也可以再次確認註冊頁面有沒有被正確的渲染(render)。

最後,完整的測試程式碼如下:

test/integration/users_signup_test.rb

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, user: { name:  "",
                               email: "user@invalid",
                               password:              "foo",
                               password_confirmation: "bar" }
    end
    assert_template 'users/new'
  end
end

assert_template 是用來檢查失敗的提交訊息有沒有重新載入正確的頁面(new action)。

因為我們在編寫測試之前,就先把應用程式碼寫好了,所以測試必然會通過(Green):

$ bundle exec rake test