Minitest คืออะไร?
Minitest เป็น Ruby testing library ช่วยให้คุณเขียน test สำหรับโค้ดได้แบบ TDD
มันคือ default testing framework ของ Rails และเป็นที่ชอบของ DHH
บางคนชอบมันเพราะความเรียบง่าย และโค้ดน้อยกว่าตัวเลือกหลัก (RSpec) มาก
ดูจากรูปนี้:

บทความนี้ไม่ได้เกี่ยวกับว่าควรเลือกตัวไหนหรือตัวไหน "ดีกว่า"
บทความนี้เกี่ยวกับ Minitest ทำงานอย่างไร
ถ้าคุณสงสัย: ใช้ตัวไหนก็ได้ที่คุณชอบ แต่น่าจะคุ้นเคยทั้งคู่ 🙂
ถ้าคุณชอบเรียนรู้ว่าสิ่งต่างๆ ทำงานยังไง คุณจะชอบบทความนี้...
ไม่ว่าคุณจะชอบ testing library ตัวไหน!
มาดูภายใต้ฝาฝน (Under The Hood)
หนึ่งในสิ่งที่แนะนำ (รวมถึงผม) คือ อ่าน source code เพราะมันเป็นวิธีดีๆ เรียนรู้ว่าสิ่งต่างๆ ทำงานยังไง และยังเรียนรู้ Ruby tricks ใหม่ๆ ที่อาจไม่เคยเห็น
นั่นคือสิ่งที่ผมทำกับ Minitest และจะแชร์สิ่งที่เรียนรู้
เริ่มจากโค้ด test จริงๆ เพื่อดูว่าเกี่ยวข้องกับวิธีการทำงานของ Minitest อย่างไร
class Thingy < Minitest::Test
def test_it_works
assert_equal 1, 1
end
end
Minitest หา testing methods (อย่าง test_it_works) และรันมันได้อย่างไร?
คำตอบคือเล็กน้อยของ metaprogramming "magic":
def self.methods_matching(re)
public_instance_methods(true).grep(re).map(&:to_s)
end
โค้ดนี้มาจากคลาส Runnable ที่กำหนดใน lib/minitest.rb โค้ดนี้หา instance methods ทั้งหมดของคลาสปัจจุบัน และเลือกเฉพาะที่ match regular expression
ดังนั้นถ้าเรียก methods_matching(/^test_/) จะได้อาร์เรย์ของชื่อเมธอดทั้งหมดที่ขึ้นต้นด้วย test_
Minitest ทำงานอย่างไร
Minitest หาเมธอด test_ แล้วเรียกมัน
เกิดขึ้นในไฟล์ lib/minitest/test.rb (เฉพาะเจาะจงที่เมธอด runnable_methods ซึ่งคืนรายการเมธอดแบบสุ่ม)
จุดสำคัญ:
นี่ทำงานได้เพราะ Minitest::Test เป็น subclass ของ Runnable
ชิ้นส่วนสุดท้ายคือ class method run บน Runnable ซึ่ง filter เพิ่มเติม แล้วเรียก run_one_method กับทุกชื่อเมธอดและ reporter object
โค้ด:
filtered_methods.each do |method_name|
run_one_method self, method_name, reporter
end
และสิ้นสุดที่การเรียก instance method run บน Minitest::Test:
capture_exceptions do
before_setup; setup; after_setup
self.send self.name
end
send เป็นเมธอด metaprogramming ให้เรียกเมธอดอื่นบนออบเจ็กต์ใดๆ ด้วย string หรือ symbol
บล็อก capture_exceptions ใช้บันทึก test failures และ exceptions ที่โค้ดของคุณ raise
def capture_exceptions # :nodoc:
yield
rescue *PASSTHROUGH_EXCEPTIONS
raise
rescue Assertion => e
self.failures << e
rescue Exception => e
self.failures << UnexpectedError.new(e)
end
วิธีอ่านโค้ดที่ผมชอบคือ โฟกัสที่ด้านหนึ่งหรือฟีเจอร์หนึ่ง แล้วปอกเปลือกทีละชั้นเหมือนหอมใหญ่
ถ้าไม่รู้ว่าอะไรหมายถึงอะไร (อย่าง keyword yield) ให้ไปค้นหา มันเป็นส่วนหนึ่งของการเรียนรู้!
สรุป
ในบทความนี้ คุณเรียนรู้ว่า Minitest ใช้ metaprogramming หา test methods และเรียกมัน รวมถึงวิธีจับ test errors และ exceptions ไว้ในอาร์เรย์เพื่อรายงาน
คุณชอบบทความประเภท "วิเคราะห์โค้ด" แบบนี้ไหม?
บอกมาในคอมเมนต์ 🙂
และ อย่าลืมแชร์บนโซเชียลมีเดียโปรดของคุณ และสมัครรับข่าวสารด้านล่างถ้ายังไม่ได้เป็นส่วนหนึ่งของ 7000+ Ruby developers ที่อยากพัฒนาทักษะ!