แก้ unit test failure ใน RailsSpace หลังอัพเกรดเป็น Rails 2.3
โพสก่อนหน้านี้จบด้วยการเจ๊งของ unit test และก็ไปอาบน้ำนอน
วันนี้เลยลองหาต้นเหตุดูว่าปัญหาเกิดจากอะไร ได้ความว่าต้นเหตุของปัญหาเกิดจาก 2 method ใน user_controller_test เท่านั้นเอง คือ cookie_expires กับ cookie_value
ปัญหาแรกคือ
1) Error:
test_login_success_with_remember_me(UserControllerTest):
NoMethodError: undefined method `expires' for "1":String
/test/functional/user_controller_test.rb:268:in `cookie_expires'
/test/functional/user_controller_test.rb:145:in
`test_login_success_with_remember_me'
ซึ่งเกิดเพราะว่าใน Rails 2.3 นั้นการเรียกใช้ cookies[symbol.to_s] จะไม่คืน cookie object แล้วแต่ว่าคืนค่าของคุ๊กกี้นั้นๆเลย (ลองดู API) ทำให้เราไม่สามารถใช้ expires ได้แล้ว
ที่ทำให้ซับซ้อนยิ่งกว่านั้น (และยังหาทางลัดใน Rails ไม่เจอ) คือเราเข้าถึงคุ๊กกี้ผ่าน @response.headers["Set-Cookie"] ได้เท่านั้น และค่าที่คืนมาจาก header นี้เป็น array ของ string ที่แต่ละ element แทนคุ๊กกี้หนึ่งอัน เช่น
(rdb:1) @response.headers["Set-Cookie"]
["remember_me=1; path=/; expires=Wed, 19-Mar-2014 16:29:09 GMT", "authorization_token=56d1799d501a6ea5f0e612d22ddba211dc4066ae; path=/; expires=Wed, 19-Mar-2014 16:29:09 GMT"]
ในกรณีนี้สิ่งที่เราต้องการ (expires) อยู่ที่ element แรกของ array ซึ่งเราสามารถแก้โค้ดเป็นแบบนี้ได้
def cookie_expires(symbol)
Time.zone.parse(@response.headers["Set-Cookie"][0].split("\;")[2].split("=")[1])
end
ไม่ได้เขียนให้อ่านง่ายมากนัก และก็ไม่ค่อยยืดหยุ่นด้วย แต่ดูเหมือนจะใช้งานได้ สิ่งที่เราทำก็คือเอา item แรกของ array ซึ่งตรงกับคุ๊กกี้ที่เราต้องการ (remember_me) มาแบ่ง string ด้วยเครื่องหมาย semicolon ก่อน แล้วก็เอา item สุดท้ายจากที่แบ่งได้ (expires) มาแบ่งด้วยเครื่องหมายเท่ากับอีกทีเพื่อเอาค่าของ expires มาแปลงเป็นเวลาเพื่อเปรียบเทียบ
แน่นอนว่าอ๊อบเจ็คต์ที่เราคืนกลับไปอาจไม่ใช่เวลาที่ตรงกับเวลาของคุ๊กกี้ที่เราเซ็ตค่าไว้ผ่านคอนโทรลเลอร์ แต่ว่าก็ยังอยู่ใน range การเปรียบเทียบของ test ได้ ซึ่งเพียงพอจะทำให้ผ่านการทดสอบ
อีกปัญหานึงที่เกิดกับ cookie_value ก็ด้วยเหตุผลเดียวกันกับที่เขียนไว้ด้านบน คือการ access hash คุ๊กกี้นั้นจะคืนค่าของคุ๊กกี้เลย ไม่ได้คืน array อีกต่อไป ทำให้เราต้องแก้เป็น
def cookie_value(symbol)
cookies[symbol.to_s]
end
หลังจากแก้ไขเรียบร้อยก็ test อีกทีเพื่อความแน่ใจ
ปล. เดาว่าการที่เราต้องเข้าถึงคุ๊กกี้ผ่าน “Set-Cookie” น่าจะเป็นผลจากการที่ Rails 2.3 เปลี่ยนมาสนับสนุน Rack เต็มรูปแบบแล้วในแบบของ middleware จึงทำให้โครงสร้างของเฟรมเวิร์คเปลี่ยนไปเก็บคุ๊กกี้ที่ HTTP request/response แทน
ยกโทษของฉันไวยากรณ์ (ฉันใช้ http://translate.google.com จากภาษาอังกฤษเป็นภาษาไทย), เพียงแต่ฉันต้องการกล่าวขอบคุณสำหรับการโพสต์นี้. การมหัศจรรย์ของเว็บไซต์ของ Google แปลผมสามารถรวบรวมเพียงพอจากบทความของคุณเพื่อแก้ปัญหาเดียวกันแน่นอนฉันคือมีกับ RailsSpace และทางรถไฟ 2.3.2. ขอขอบคุณอีกครั้ง!
Happy reader
เมษายน 5, 2009 at 6:58 am