(นี่คือ excerpt สั้นจาก Practicing Rails สมัครที่นี่รับ chapter แรกฟรี!)
ทำงานกับแอปใหม่ Rails generate test ให้:
require 'test_helper' class BugTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end Uncomment ตั้งชื่อ พร้อมเขียน test แล้วใช่ไหม? แตต่อไปไหน? เขียนอะไรก่อน? Test code ควรเป็นยังไง?
ถ้าฟอลโลว์ pattern เรียบง่าย จะเปลี่ยน stub lines กลายเป็น test cases ชัดเจน และ well-structured
Three-Phase Test Pattern
Test cases ควรทำงาน 3 phases:
- Set stuff up ก่อน ("Arrange")
- ทำบางอย่าง ("Act")
- ตรวจสอบว่าสิ่งที่คาดหวัง เกิดขึ้นจริง ("Assert")
เช่น ทดสอบ method บน array ใน Ruby ตาม pattern นี้ test อาจเป็น:
test "Array#sort will sort an array of numbers" do # arrange unsorted_array = [7, 4, 2, 3] # act sorted_array = unsorted_array.sort # assert assert_equal [2, 3, 4, 7], sorted_array end ง่ายพอ แตทุกส่วนของ test มีที่ไป และแต่ละ stage เกือดบอกว่าเขียนยังไง
บางครั้งไม่ต้อง Arrange phase หรือ Act และ Assert รวมกัน แตยังช่วยให้คิด 3 phases ตอนเขียน tests
Assert Phase Gotcha
มี trick ที่ Assert phase: ไม่ควรใช้ logic เดียวกับ Act phase ใน Assert phase ควรหาคำตอบทางเดียวกัน 2 ทาง ไม่เช่นนั้น ไม่เจอบั๊กในโค้ดที่เรียก เพราะมันแค่ถูกเรียกซ้ำใน Assert
เช่น ทำ math:
test "average returns the average of a set of numbers" do # arrange numbers = [1, 2, 3, 4] # act average = numbers.average # assert # นี่แย่ assert_equal [1, 2, 3, 4].average, average # นี่ดีกว่า assert_equal 2.5, average end เรียก [1, 2, 3, 4].average ซ้ำใน Assert แย่ เพราะ average คืน อะไรก็ได้ assertion ก็ยัง pass
ตรงนี้ชัด แตแม้ซับซ้อนขึ้น ให้แน่ใจว่าไม่ได้แค่รันโค้ดเดียวกัน 2 ครั้ง ไม่งั้นแค่ verify ว่า method ถูกเรียก ไม่ใช่ว่าทำงานเหมือนคาดหวัง
ปกติ easiest way หาทางที่ 2 ไปคำตอบ คือ หาคำตอบเองมือ แล้ว hardcode อาจ brittle แตดีกว่า tests พังโดยไม่รู้
ทำไม Three Phases?
ถ้าแยก tests 3 phases จะได้คำถามง่ายขึ้น แทน "เขียน test ยังไง?" โฟกัสแต่ละ phase: "setup ยังไง?", "ทดสอบอะไร?", "คำตอบควรเป็นยังไง?"
คำถามเหล่านี้ยังอาจไม่ง่าย แตคำตอบจะง่ายกว่าคิดทั้ง test พร้อมกัน และถ้าดีใจ อาจ share phases ระหว่าง related tests ทำ test ต่อไปไม่เจ็บปวดเท่าไหร่