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

เชี่ยวชาญ VCR ใน Ruby: เพิ่มประสิทธิภาพและความน่าเชื่อถือของเทสต์

ถ้าแอปพลิเคชัน Ruby ของคุณใช้ API ภายนอกใดๆ คุณน่าจะเผชิญปัญหา เทสต์ช้าและขีดจำกัดอัตรา API (API rate limits)

โซลูชันคืออะไร?

คุณอาจจะ stub เมธอด HTTP จากไลบรารี client ด้วยมือ และคืนคำตอบที่กำหนดไว้ล่วงหน้า

แต่มันเป็นงานเยอะและโค้ด醜陋!

โซลูชันที่ดีกว่าคือใช้ การรวมพลังของ gems เช่น Webmock + VCR

WebMock จับคำขอ HTTP จากไลบรารี HTTP ทั่วไป เช่น:

  • net/http
  • Faraday
  • RestClient
  • ...อีกเยอะ!

สิ่งนี้มีประโยชน์แล้ว แตคุณยังต้องให้ข้อมูลคำตอบ

นี่คือที่มาของ VCR...

VCR ทำงานร่วมกับ WebMock เพื่อ บันทึกการตอบสนอง HTTP ที่โค้ดของคุณสร้าง

การบันทึกเหล่านี้เรียกว่า "cassettes" (คาสเซ็ต)

เมื่อคุณรันเทสต์:

VCR จะโหลดไฟล์ cassette และคืนคำตอบที่บันทึกไว้ คุณจะได้การตอบสนองเร็วขึ้น เพราะไม่ต้องขอ API จริง

มา看看ตัวอย่างโค้ด!

ตัวอย่างโค้ด VCR

สำหรับตัวอย่างนี้ เราจะใช้ RSpec เพราะมัน integrate กับ VCR ได้ดีกว่า ตามที่คุณจะเห็นในส่วนต่อไป

โค้ดที่เราต้องการทดสอบ:

require "faraday"
require "json"
class Github
  def self.user(name)
    url = "https://api.github.com/users/#{name}"
    data = Faraday.get(url).body
    JSON.parse(data, symbolize_names: true)
  end
end

มันทำคำขอไปที่ Github API เพื่อรับข้อมูลผู้ใช้เฉพาะ ค่อนข้างเรียบง่าย แตจะช่วยเราเรียนรู้ VCR

เทสต์สำหรับโค้ดนี้อาจเป็นแบบนี้:

require "rspec/autorun"
require_relative "github_api_example"
describe Github do
  let(:user_response) { Github.user("ruby") }
  it "can fetch & parse user data" do
    expect(user_response).to be_kind_of(Hash)
    expect(user_response).to have_key(:id)
    expect(user_response).to have_key(:type)
  end
end

นี่จะเรียก API จริง และผ่าน แตใช้เวลาประมาณครึ่งวินาที

ครึ่งวินาทีสำหรับ หนึ่งเทสต์!

อาจดูไม่มาก แต่วิ่งลองนึกภาพว่าคุณมี 100 เทสต์ นั่นคือ 50 วินาทีในการรันทั้งหมด

เวลาแก้ไขแล้ว...

มาเพิ่ม VCR ด้วยโค้ดนี้:

require "vcr"
VCR.configure do |c|
  c.cassette_library_dir = "spec/vcr"
  c.hook_into :webmock
end

คุณสามารถเพิ่มโค้ดนี้ในไฟล์ test_helper เพื่อให้พร้อมใช้สำหรับเทสต์ทั้งหมด

ด้วยบล็อก configure นี้ คุณบอก VCR ว่าจะบันทึกไฟล์ cassette ที่ไหน และเปิดใช้งาน WebMock integration

ถ้าคุณใช้ Faraday หรือ Excon VCR สามารถ hook เข้าไปได้โดยตรง

แค่แทน :webmock ด้วย :faraday หรือ :excon

ต่อไป:

คุณต้องบอก VCR ชื่อ cassette และโค้ดไหนควรทำงานภายใต้ cassette นั้น

วิธีทำ:

let(:user_response) do
  VCR.use_cassette("github/user") { Github.user("ruby") }
end

เมื่อคุณรันเทสต์ VCR จะสร้างไฟล์ภายใต้ cassette_library_dir ในกรณีนี้ชื่อไฟล์จะเป็น spec/vcr/github/user.yaml หากคุณติดตามมาอยู่ คุณอาจอยากดูมัน

ถ้าผมรันเทสต์ตอนนี้ มันจะ เร็วขึ้นมาก

จริงๆ แล้ว...

มันใช้แค่ 0.01 วินาที!

"An HTTP request has been made that VCR does not know how to handle"

หากคุณเจอข้อความข้อผิดพลาดนี้ หมายถึงหนึ่งในสองอย่าง:

1. คุณพยายามทำคำขอ HTTP พร้อม VCR เปิดอยู่ แต่นอกบล็อก VCR.use_cassette

วิธีแก้: โดยค่าเริ่มต้น VCR + WebMock บล็อกคำขอ HTTP ทั้งหมด คุณสามารถเปลี่ยนได้ด้วยตัวเลือกการตั้งค่า เพิ่มบล็อก VCR ที่ขาดหายไป หรือใช้ RSpec metadata (ส่วนต่อไป)

2. คุณพยายามทำคำขอที่ต่างออกไป และใช้ cassette ที่ไม่ตรงกับ URL นี้ ตัวอย่าง หากคุณ request ในเทสต์ /users/ruby cassette ถูกสร้างเฉพาะสำหรับ URL นี้ หากคุณเปลี่ยนเทสต์เป็น /users/apple คุณจะเห็นข้อผิดพลาดนี้ เพราะ cassette เป็นสำหรับ URL อื่น

วิธีแก้: ใช้ cassette ต่างกันสำหรับ URL ต่างกัน เปิดโหมด recording new_episodes (vcr: { record: :new_episodes }) หรือลบ cassette เก่าหลังอัปเดต URL request

วิธีใช้ RSpec Metadata

เมธอด VCR.use_cassette เป็นวิธีที่ดีในการใช้ gem นี้

แต่...

คุณยังสามารถให้ VCR สร้าง cassettes ให้อัตโนมัติได้

อย่างไร?

เพิ่มนี้ภายในบล็อก VCR.configure:

c.configure_rspec_metadata!

ตอนนี้คุณสามารถเปิดใช้งาน VCR สำหรับเทสต์เฉพาะ (it block) หรือกลุ่มเทสต์ (describe)

เช่นนี้:

describe Github, :vcr do
  # ...
end

สิ่งนี้จะสร้างไฟล์ cassette ชื่อตาม คำอธิบายของเทสต์:

spec/vcr/
└── Github
    ├── can_parse_user_data.yml
    └── can_test_vcr.yml

สังเกตว่านี่จะสร้าง cassette ต่อเทสต์...

แม้สองเทสต์จะทำคำขอเดียวกันและใช้ข้อมูลเดียวกัน VCR จะสร้าง cassette แยกสำหรับแต่ละอัน

ตัวเลือกและเคล็ดลับ VCR ที่มีประโยชน์

หากคุณมีปัญหากับ cassettes หรืออยากข้อมูลรุ่นใหม่ คุณสามารถ ลบไฟล์ cassette

VCR จะบันทึกคำตอบ API ใหม่ และอาจแก้ปัญหาของคุณ

แตถ้ามันไม่ได้?

คุณสามารถเปิด debug mode ใน VCR.configure:

VCR.configure do |c|
  # ...
  c.debug_logger = $stderr
end

สิ่งนี้อาจให้เอาต์พุทเยอะ จำกัดเทสต์เฉพาะที่คุณสนใจ

ต่อไป:

สมมติว่ามี API keys หรือข้อมูลละเอียดอ่อนอื่นเป็นส่วนหนึ่งของคำตอบ API...

คุณอาจอยากกรองข้อมูลนั้นออกจากการบันทึก

วิธีทำ:

VCR.configure do |c|
  # ...
  c.define_cassette_placeholder("<API_KEY>", ENV["API_KEY"])
end

สรุป

คุณได้เรียนรู้วิธีใช้ gems WebMock และ VCR เพื่อเขียนเทสต์สำหรับแอป Ruby โดยไม่ต้องรอคำตอบจาก API ภายนอก!

เชี่ยวชาญ VCR ใน Ruby: เพิ่มประสิทธิภาพและความน่าเชื่อถือของเทสต์

ถ้าชอบ อย่าลืมแชร์บทความนี้เพื่อให้คนอื่นเพลิดเพลินไปกับมัน

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