Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีใช้ RSpec Mocks (การสอนทีละขั้นตอน)

การเยาะเย้ยใน RSpec คืออะไร

(หรือล้อเลียนโดยทั่วไป เพราะนี่ไม่ใช่แนวคิดเฉพาะของ RSpec)

ล้อเลียนคือวัตถุที่ใช้ในการทดสอบ .

คุณใช้ mocks เพื่อทดสอบการโต้ตอบระหว่างสองอ็อบเจ็กต์ แทนที่จะทดสอบค่าเอาท์พุตเหมือนอย่างที่คาดไว้ทั่วไป

ตัวอย่างเช่น :

คุณกำลังเขียน API ที่พลิกภาพ

แทนที่จะเขียนโค้ดปรับแต่งภาพของคุณเอง คุณใช้อัญมณีอย่าง mini_magick .

คุณต้องการทดสอบการโต้ตอบระหว่างโค้ดของคุณกับการพึ่งพาภายนอก .นี้ … ดังนั้น คุณจึงเขียนแบบจำลองที่คาดว่าจะเรียกใช้วิธีการที่ถูกต้องบน ImageProcessor ชั้นเรียน

ซึ่งหมายความว่าคุณจะไม่พลิกภาพ (การทำงานช้า) ทุกครั้งที่ทำการทดสอบ

มันทำงานอย่างไร

การเยาะเย้ยมาแทนที่วัตถุดั้งเดิม ดังนั้นจึงไม่มีการเรียกวิธีการที่แท้จริง

ถึงเวลาสำหรับตัวอย่างโค้ดแล้ว!

ตัวอย่าง RSpec จำลอง

นี่คือ ImageFlipper ทดสอบ:

RSpec.describe "ImageFlipper" ทำ "เรียกเมธอด flip ด้วยอาร์กิวเมนต์ที่ถูกต้อง" do mock =double("mini_magick") expect(mock).to receive(:flip).with("ruby.jpg") img =ImageFlipper.new(จำลอง) img.flip("ruby.jpg") สิ้นสุด

ด้วยการทดสอบนี้ เราสามารถเขียนโค้ดของเราโดยใช้ TDD

ก่อน :

เราต้องเขียน ImageFlipper ชั้นเรียน

ถูกใจสิ่งนี้ :

คลาส ImageFlipper def initialize (image_processor) @image_processor =image_processor endend

นอกจากนี้เรายังต้องการ flip วิธีการ:

def flip(file_name)end

ตอนนี้เราได้รับข้อเสนอแนะนี้จาก RSpec:

Failures:1) ImageFlipper เรียกใช้เมธอด flip ด้วยอาร์กิวเมนต์ที่ถูกต้อง Failure/Error:expect(mock).to receive(:flip).with("ruby.jpg") (Double "mini_magick").flip(" ruby.jpg") ที่คาดไว้:1 ครั้งโดยมีอาร์กิวเมนต์:("ruby.jpg") ได้รับ:0 ครั้ง # ./rspec-mocks.rb:6:in `block (2 ระดับ) ใน '

นี่กำลังบอกว่า flip เมธอดถูกเรียก 0 ครั้ง แต่คาดว่าจะเรียก 1 ครั้ง

คุณสามารถทำให้การทดสอบนี้ผ่านโดยให้สิ่งที่ต้องการ :

def flip(file_name) @image_processor.flip(file_name)end

และแล้ว เรามีการทดสอบผ่าน :

.เสร็จสิ้นใน 0.00751 วินาที (ไฟล์ใช้เวลาในการโหลด 0.11157 วินาที)1 ตัวอย่าง, 0 ความล้มเหลว

มาทบทวนกัน:เราทำอะไรลงไปบ้าง

เราได้สร้าง ImageFlipper คลาสที่ใช้ image_processor .

โปรเซสเซอร์นี้ตอบสนองต่อ flip วิธีการ

เราใช้การเยาะเย้ยเพื่อทดสอบว่าวิธีนี้ถูกเรียกครั้งเดียวด้วยการโต้แย้งหรือไม่

ฉันรู้.

ตัวอย่างนี้ง่าย

แต่คุณสามารถจินตนาการถึงการใช้งาน ImageFlipper . อย่างสมบูรณ์ ที่ตรวจสอบว่ามีไฟล์อยู่หรือไม่ หากเป็นรูปภาพที่ถูกต้อง ฯลฯ

ความแตกต่างระหว่างการเยาะเย้ยและการทดสอบค่า

ในการทดสอบปกติ คุณตรวจสอบ ค่าส่งคืนของเมธอด :

“วิธีนี้ได้ภาพที่พลิกกลับหรือไม่”

เมื่อใช้ล้อเลียน คุณกำลังทดสอบพฤติกรรม :

“เราบอกผู้อื่นถึงสิ่งที่ควรทำ ด้วยข้อมูลที่ถูกต้อง และจำนวนครั้งที่เราต้องการหรือไม่”

เยาะเย้ย vs สตับ

อีกประเด็นที่สับสนคือการเปรียบเทียบการล้อเลียนและสตับ

ต่างกันอย่างไร

  • ต้นขั้วเป็นเพียงวิธีการที่มีคำตอบสำเร็จรูป ไม่สนใจพฤติกรรม
  • การเยาะเย้ยคาดว่าจะเรียกเมธอด หากไม่เรียก การทดสอบจะล้มเหลว

นี่คือโครงใน RSpec :

stub =double("json")allow(stub).to receive(:response) do {"blog"=>"rubyguides.com", "rating"=>"5/5"}.to_jsonend

ก่อน>

allow วิธีการคือสิ่งที่ทำให้สิ่งนี้เป็นโครง

เราอนุญาตให้วัตถุทดสอบของเรา double("json") เพื่อรับและตอบสนองต่อวิธีนี้ แต่ เราไม่ได้ตรวจสอบว่ามีการเรียกหรือไม่ .

นั่นคือความแตกต่าง!

วิธีใช้คู่ที่ยืนยันแล้ว

ข้อเสียอย่างหนึ่งของ mocks &stubs คือคุณสามารถใช้วิธีที่ไม่มีอยู่ในโค้ดที่ใช้งานจริงได้

เพราะชื่อเมธอดเปลี่ยนไป… หรือบางทีคุณอาจพิมพ์ผิด!

พบกับคู่ที่ยืนยันแล้ว .

ดับเบิลที่ตรวจสอบแล้วสามารถใช้เป็นต้นขั้วได้ (allow ) หรือล้อเลียน (expect ) &มันจะตรวจสอบว่ามีวิธีการที่ใช้ชื่อนี้หรือไม่

ตัวอย่าง :

mock =instance_double(ImageProcessor)

สิ่งนี้จะทำให้เกิดข้อผิดพลาดหากไม่มีวิธีการ:

1) ImageFlipper เรียกใช้เมธอด flip ด้วยอาร์กิวเมนต์ที่ถูกต้อง Failure/Error:expect(mock).to receive(:flip).with("ruby.jpg") คลาส ImageProcessor ไม่ได้ใช้เมธอดอินสแตนซ์:flip

แต่จะทำงานได้ถูกต้องหากมีวิธีการ

จำลองการคืนค่า

กลับไปเยาะเย้ยกันเถอะ

ใน ตัวอย่าง last ที่แล้ว เรามีสิ่งนี้:

คาดหวัง(เยาะเย้ย).ที่จะได้รับ(:พลิก).กับ("ruby.jpg")

เมื่อรหัสของคุณเรียก flip ตัวจำลองจะคืนค่า nil .

หากโค้ดคาดหวังค่าอื่นที่ไม่ใช่ศูนย์ จะส่งผลให้เกิดข้อผิดพลาด

คุณสามารถแก้ไขได้โดยสร้างผลลัพธ์จำลอง

ถูกใจสิ่งนี้ :

คาดหวัง(เยาะเย้ย).ที่จะได้รับ(:พลิก).กับ("ruby.jpg").and_return("ruby-flipped.jpg")

วิธีการจำลองวิธีการอินสแตนซ์

สมมติว่าคุณมีรหัสดังนี้:

คลาส NumberGenerator def สุ่ม "A" * rand(1..10) endend

วิธีนี้ยากต่อการทดสอบเนื่องจากการสุ่ม

RSpec ช่วยให้คุณเยาะเย้ยหรือ stub rand .

ถูกใจสิ่งนี้ :

มัน "สร้างตัวเลขสุ่ม" ทำเครื่องกำเนิดไฟฟ้า =NumberGenerator.new allow(generator).to receive(:rand).and_return(5) expect(generator.random).to eq("AAAAA")end

ตอนนี้ :

rand ส่งคืนค่าคงที่เพื่อให้คุณใช้ทดสอบผลลัพธ์ของวิธีการได้

ตามหลักการแล้ว คุณต้องการฉีดการพึ่งพาของคุณ (rand ในกรณีนี้) เพื่อให้คุณสามารถควบคุมได้ การฉีดการพึ่งพาหมายความว่า คุณส่งผ่านเป็นพารามิเตอร์ ไม่มีอะไรหรูหรา

แต่บางครั้งก็สะดวกกว่าถ้าจะใช้วิธี stub วิธีนี้

เมื่อใดควรใช้การเยาะเย้ย

ตอนนี้สำหรับคำถามใหญ่…

คุณควรใช้การเยาะเย้ยเมื่อใด

การพัฒนาซอฟต์แวร์เป็นหัวข้อที่ซับซ้อน

แต่มีหลักเกณฑ์บางประการที่คุณสามารถปฏิบัติตามได้ :

  1. หากเมธอดภายใต้การทดสอบคืนค่า &มันไม่มีผลข้างเคียง (การสร้างไฟล์ การส่งคำขอ API เป็นต้น) คุณไม่จำเป็นต้องมีการจำลอง เพียงตรวจสอบมูลค่าที่ส่งคืน
  2. หากวิธีการทำงานกับวัตถุภายนอกและส่งคำสั่งไปยังวัตถุเหล่านั้น คุณสามารถจำลองการโต้ตอบกับวัตถุเหล่านี้ได้
  3. หากวิธีการร้องขอข้อมูลจากบริการภายนอก (เช่น API) คุณสามารถใช้ต้นขั้วเพื่อให้ข้อมูลนี้เพื่อวัตถุประสงค์ในการทดสอบ

คุณต้องการจองการเยาะเย้ยเพื่อโต้ตอบกับโลกภายนอก .

กล่าวอีกนัยหนึ่ง…

หลีกเลี่ยงการเยาะเย้ยชั้นเรียนของแอปพลิเคชันของคุณเอง!

ทำไม?

เพราะนั่นช่วยส่งเสริมการทดสอบของคุณร่วมกับรายละเอียดการใช้งาน &ทำให้โค้ดของคุณเปลี่ยนแปลงได้ยากขึ้น .

ข้อยกเว้นเพียงอย่างเดียวคือสำหรับคลาสที่ห่อหุ้มโค้ดของบุคคลที่สาม

ดูวิดีโอนี้เพื่อเรียนรู้เพิ่มเติม :

สรุป

คุณได้เรียนรู้เกี่ยวกับ RSpec mocks, stubs &Verified doubles!

กรุณา แชร์บทความนี้ เพื่อให้ผู้คนสามารถเพลิดเพลินและได้รับประโยชน์จากเนื้อหานี้มากขึ้น

ขอบคุณที่อ่านนะคะ 🙂