ดูเหมือนว่าผู้คนจะอธิบายวิธีพื้นฐานบางอย่างที่แตกต่างกันออกไป แต่ก็before(:all)
ไม่ได้อธิบายว่าทำไมจึงควรใช้
ฉันเชื่อว่าตัวแปรอินสแตนซ์ไม่มีสถานที่ที่ใช้ในข้อกำหนดส่วนใหญ่ส่วนหนึ่งมาจากเหตุผลที่กล่าวถึงในคำตอบนี้ดังนั้นฉันจะไม่พูดถึงตัวแปรเหล่านี้เป็นตัวเลือกที่นี่
ปล่อยให้บล็อก
โค้ดภายในlet
บล็อกจะถูกเรียกใช้เมื่อมีการอ้างอิงเท่านั้นและขี้เกียจโหลดซึ่งหมายความว่าการสั่งบล็อกเหล่านี้ไม่เกี่ยวข้อง สิ่งนี้ช่วยให้คุณมีพลังงานจำนวนมากในการลดการตั้งค่าซ้ำ ๆ ผ่านข้อกำหนดของคุณ
ตัวอย่างหนึ่ง (ที่เล็กมากและสร้างขึ้น) คือ:
let(:person) { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }
context 'with a moustache' do
let(:has_moustache) { true }
its(:awesome?) { should be_true }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
คุณสามารถเห็นได้ว่าhas_moustache
มีการกำหนดไว้แตกต่างกันในแต่ละกรณี แต่ไม่จำเป็นต้องทำซ้ำsubject
คำจำกัดความ สิ่งสำคัญที่ควรทราบก็คือlet
บล็อกสุดท้ายที่กำหนดในบริบทปัจจุบันจะถูกใช้ นี่เป็นสิ่งที่ดีสำหรับการตั้งค่าเริ่มต้นที่จะใช้สำหรับข้อกำหนดส่วนใหญ่ซึ่งสามารถเขียนทับได้หากจำเป็น
ตัวอย่างเช่นการตรวจสอบค่าส่งคืนcalculate_awesome
ว่าส่งผ่านperson
โมเดลด้วยการtop_hat
ตั้งค่าเป็นจริง แต่ไม่มีหนวดจะเป็น:
context 'without a moustache but with a top hat' do
let(:has_moustache) { false }
let(:person) { build(:person, top_hat: true) }
its(:awesome?) { should be_true }
end
สิ่งที่ควรทราบอีกประการหนึ่งเกี่ยวกับการบล็อกให้ไม่ควรใช้หากคุณกำลังค้นหาบางสิ่งที่บันทึกไว้ในฐานข้อมูล (กล่าวคือLibrary.find_awesome_people(search_criteria)
) เนื่องจากจะไม่ถูกบันทึกลงในฐานข้อมูลเว้นแต่จะได้รับการอ้างอิงแล้ว let!
หรือbefore
บล็อกคือสิ่งที่ควรใช้ที่นี่
นอกจากนี้ไม่เคยใช้before
เพื่อเรียกการทำงานของlet
บล็อกนี่คือสิ่งที่let!
สร้างขึ้นเพื่อ!
ปล่อย! บล็อก
let!
บล็อกจะถูกดำเนินการตามลำดับที่กำหนดไว้ (เหมือนกับบล็อกก่อนหน้า) ความแตกต่างหลักอย่างหนึ่งของก่อนบล็อกคือคุณได้รับการอ้างอิงอย่างชัดเจนถึงตัวแปรนี้แทนที่จะต้องถอยกลับไปที่ตัวแปรอินสแตนซ์
เช่นเดียวกับlet
บล็อกหากlet!
กำหนดหลายบล็อกด้วยชื่อเดียวกันล่าสุดคือสิ่งที่จะใช้ในการดำเนินการ ความแตกต่างหลักคือการlet!
บล็อกจะถูกดำเนินการหลายครั้งหากใช้เช่นนี้ในขณะที่let
บล็อกจะดำเนินการครั้งสุดท้ายเท่านั้น
ก่อน (: each) บล็อก
before(:each)
เป็นค่าดีฟอลต์ก่อนบล็อกดังนั้นจึงสามารถอ้างอิงได้before {}
แทนที่จะระบุเต็มbefore(:each) {}
ในแต่ละครั้ง
เป็นความชอบส่วนตัวของฉันที่จะใช้before
บล็อกในสถานการณ์หลักบางอย่าง ฉันจะใช้ก่อนบล็อกถ้า:
- ฉันใช้การเยาะเย้ยถากถางหรือดับเบิล
- มีการตั้งค่าขนาดที่เหมาะสม (โดยทั่วไปนี่เป็นสัญญาณว่าลักษณะโรงงานของคุณยังไม่ได้ตั้งค่าอย่างถูกต้อง)
- มีตัวแปรหลายตัวที่ฉันไม่จำเป็นต้องอ้างอิงโดยตรง แต่จำเป็นสำหรับการตั้งค่า
- ฉันกำลังเขียนการทดสอบตัวควบคุมการทำงานในรางและฉันต้องการดำเนินการตามคำขอเฉพาะเพื่อทดสอบ (เช่น
before { get :index }
) แม้ว่าคุณจะสามารถใช้subject
สิ่งนี้ได้ในหลาย ๆ กรณี แต่บางครั้งก็รู้สึกชัดเจนกว่าหากคุณไม่ต้องการข้อมูลอ้างอิง
หากคุณพบว่าตัวเองเขียนbefore
บล็อกขนาดใหญ่สำหรับข้อมูลจำเพาะของคุณให้ตรวจสอบโรงงานของคุณและตรวจสอบให้แน่ใจว่าคุณเข้าใจลักษณะและความยืดหยุ่นของพวกเขาอย่างถ่องแท้
ก่อน (: ทั้งหมด) บล็อก
สิ่งเหล่านี้จะถูกดำเนินการเพียงครั้งเดียวก่อนข้อกำหนดในบริบทปัจจุบัน (และลูก ๆ ) สิ่งเหล่านี้สามารถใช้เพื่อประโยชน์อย่างมากหากเขียนอย่างถูกต้องเนื่องจากมีบางสถานการณ์ที่สามารถลดการดำเนินการและความพยายามลงได้
ตัวอย่างหนึ่ง (ซึ่งแทบจะไม่มีผลต่อเวลาดำเนินการเลย) คือการเยาะเย้ยตัวแปร ENV สำหรับการทดสอบซึ่งคุณควรทำเพียงครั้งเดียว
หวังว่าจะช่วยได้ :)