ที่นี้เราจะมาลอง สร้าง test กันขึ้นมาจริงๆ สักทีนะครับ ผมจะลองสมมุติว่าใน application ของเรามี login system นะครับ

เราต้องการทำสอบ function reset password ที่อยู่ใน login system ว่า Behavior มันถูกต้องหรือไม่ พูดง่ายๆ ก็คือใน function reset password นั้นมันทำงานตามขั้นตอนที่เราวางแผนไว้หรือไม่

ผมจะลอง Define ขั้นตอนการทำงานของ Reset password ไว้คราวๆ ครับ

For people who forget their password:

– Should be able to call reset password function

– Should be able to sent notification if email is valid

– Should be able to redirect to login page

(ขอแปลเป็นไทยนิดนึงนะครับ จะได้เข้าใจง่ายขึ้น)

สำหรับคนที่ลืม password:

– ควรที่จะสามารถเรียก reset password fuction ได้

– ถ้าอีเมลถูกก็ควรที่จะได้รับ อีเมล สำหรับ new password

– หลังจากนั้นควรที่จะ redirect กลับไปหน้า login

เห็นไหมครับ การที่เราเขียน specification ออกมาแบบนี้ทำให้เราสามารถเห็นภาพรวมของ Reset Password ว่ามันทำงานเป็นขั้นเป็นตอนอย่างไร

เนื่องจากว่า RSpec มีรูปแบบภาษาของมันเอง ฉะนั้นเราทำความเข้าใจกับภาษาของมันก่อน แต่ว่าอย่าเพิ่งบ่นนะครับ เพราะว่ามันง่ายมากเหมือนภาษาพูดซะมากกว่า

1. ไปที่ folder rspec ในโปรเจค เข้าไปที่ controllers แล้วก็สร้างไฟล์ user_controller_spec.rb (ใครที่ยังไม่มี folder นี้ให้กลับไปอ่านภาคสองก่อนนะครับ)

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe UserController, "A for people who forget the password" do

  before(:all) do

  end

  it "Should be able to call reset password function" do
      pending "Not done yet"
  end

  it "Should be able to sent notification if email is valid" do
      pending "Not done yet"
  end

  it "Should be able to redirect to login page" do
      pending "Not done yet"
  end

end

ตอนนี้หลังจากที่ save file นี้แล้วหากใครรัน autotest เอาไว้อยู่มันก็จะขึ้นว่า pending อยู่ 3 tests นะครับ เพราะว่าเรายังไม่ได้ใส่อะไรลงไปเพื่อเทสกันเลย

2. สร้าง Controller ขึ้นมาเพื่อที่จะเทส ผมจะตั้งชื่อว่า UserController แล้วกานนะครับ

class UserController < ApplicationController
   # Empty Controller
end
&#91;/sourcecode&#93;

แล้วอย่าลืมกลับไปใช้ชื่อที่เราต้องการจะเทสตรง <span class="caps">CONTROLLER</span>_NAME_HERE ในไฟล์แรกด้วยนะครับ

3. กลับมาเขียนเทสที่ไฟล์แรกกาน เราจะมาเริ่มดูจาก behavior แรกกานก่อนเลย


it “Should be able to call reset password function” do
   pending “Not done yet”
end

เราจะทำการเทสว่าถ้า user ลืม password แล้วเค้าจะสามราถเรียก reset password ได้ไหม

it “Should be able to call reset password function” do
   #pending “Not done yet” เราทำการคอมเมนต์ pending ไว้นะครับ
   #ทำการเรียก reset password ใน UserController
   get :reset_password

ผลลัพธที่ได้หลังจากเซฟไฟล์ก็คือ

Picture 5.png

1 test file ครับ เพราะว่าอะไร นั้นก็เพราะว่า ใน UserController ของเรายังไม่มี reset password ให้เรียกนั้นเองครับ

เพราะฉะนั้นเราก็ทำการเพิ่ม reset_password action ลงไปใน UserController ซะก็เรียบร้อย

class UserController < ApplicationController
   def reset_password
     # Empty Action
   end
end
&#91;/sourcecode&#93;

ผลลัพธ์ที่ได้ก็คือ ผ่านครับ
<img src="https://whenurnotaround.files.wordpress.com/2008/10/picture-6.png" alt="Picture 5.png" width="480" height="300" />

4. ลองมาดูต่อกันที่ behavior ทีสองกานว่าหลังจารเราสามารถที่จะเรียก reset_password ใน action ได้แล้ว มันจะต้องทำอะไรต่อไป


it “Should be able to sent notification if email is valid” do
   #pending “Not done yet”
   get :reset_password #เรียก reset_password action
   @user = mock_model(User, :email => 'paul@safecoms.com') # ทำการสร้าง object ขึ้นมาเพื่อเทส
   User.stub!(:find_by_email).and_return(@user.email) # ทำการเรียก find_by_email เพื่อเชคว่ามีอีเมลอยู่จริงหรือไม่
   flash[:notice].should == 'email sent' # โชว์ข้อความว่าได้ reset password แล้ว
end

ใน UserController

class UserController < ApplicationController def reset_password @user = User.find_by_email(params[:email]) # ทำการเชคว่าเป็น valid user รึป่าว # ส่งอีเมล flash[:notice] = "email sent" end end [/sourcecode] แค่นี้ก็เรียบร้อยแล้วครับ เห็นไหมครับว่าการที่เราทำ BDD เอาไว้ก่อนทำให้เราเห็นภาพรวมทั้งหมดของ function ผมว่าการทำเทสแบบ BDD นั้นทำให้เราวางแผนการ และขั้นตอนทั้งหมดของการทำงานไว้ก่อนที่จะลงมือเขียนโค้ด นี้น่าจะเป็นอีกทางเลือกหนึ่งของการทำเทสที่ดีในตอนนี้ก็ว่าได้