RSpec으로 VCR 구성
좋은 개발자로서 우리는 코드베이스에 사양을 추가하여 모든 것이 제대로 테스트되었는지 확인합니다.
테스트 스위트를 더 빠르고 일관성 있게 유지하려면 http 요청을 모의 처리해야 합니다. 이를 달성하는 간단하고 좋은 방법은 요청에 대한 http 응답을 쉽게 모방할 수 있는 Webmock gem을 사용하는 것입니다.
# spec/webmock_spec.rb
stub_request(:get, 'https://example.com/service').
to_return(status: 200 body: '{"a": "abc"}')
Example of mock using Webmock
이것은 잘 작동하지만 작업이나 비즈니스 로직을 수행하기 위해 많은 요청을 수행해야 하는 경우 모의가 복잡해지고 유지하기 어려워집니다.
예: 시스템에서 일부 제품을 가져와야 하지만 이러한 제품이 다른 범주로 구분되어 있고 필요한 제품을 얻기 위해 모든 범주를 가져오기 위해 제품을 검색하기 위해 반복한다고 가정해 보겠습니다.
let(:categories_endpoint) { "https://example.com/categories" }
let(:categories_response) do
[{id: 'category-one-id'}, {id: 'category-two-id', name: ''}].to_json
end
let(:first_category_endpoint) { "#{categories_endpoint}/category-one-id" }
let(:first_category_response) do
{
products_links: [
{link: 'https://example.com/categories/categor-one-id/product-one'}
]
}.to_json
end
let(:second_category_endpoint) { "#{categories_endpoint}/category-two-id" }
let(:second_category_response) do
{
products_links: [
{link: 'https://example.com/categories/categor-two-id/other-product'}
]
}.to_json
end
let(:first_product_endpoint) { 'https://example.com/categories/categor-one-id/product-one' }
let(:first_product_response) { read_fixture('fixtures/products/first_product.json') }
let(:second_product_endpoint) { 'https://example.com/categories/categor-two-id/other-product' }
let(:second_product_response) { read_fixture('fixtures/products/second_product.json') }
before do
stub_request(:get, categories_endpoint).to_return(status: 200, body: categories_response)
stub_request(:get, first_category_endpoint).to_return(status: 200, body: first_category_response)
stub_request(:get, second_category_endpoint).to_return(status: 200, body: second_category_response)
stub_request(:get, first_product_endpoint).to_return(status: 200, body: first_product_response)
stub_request(:get, second_product_endpoint).to_return(status: 200, body: second_product_response)
end
A possible mock for the example
우리가 볼 수 있듯이 모의 구성이 방대하고 세 번째 범주를 추가해야 하는 경우 이러한 구성이 훨씬 더 증가하여 읽기 및 유지 관리가 어려워집니다.
또 다른 문제는 우리가 응용 프로그램의 다른 위치에서 사용할 수 있는 것을 만드는 데 시간을 보내고 있다는 것입니다.
이를 피하는 방법은 VCR gem 을 사용하는 것입니다.
VCR 보석
VCR은 테스트 스위트에서 http 상호 작용을 기록하고 향후 실행에서 이러한 상호 작용을 재생할 수 있도록 하는 보석입니다.
VCR 사용
VCR 사용법은 다음과 같이 매우 간단합니다.
# Configure it
VCR.configure do |config|
config.cassette_library_dir = "fixtures/vcr_cassettes"
config.hook_into :webmock
end
# Uses it
it 'does something' do
VCR.use_cassette('my_cassete') do
expect(do_request.body).to eql({success: true}.to_json)
end
end
구성은 간단하지만 사용법이 약간 짜증나서 모든 HTTP 상호 작용을 블록으로 래핑해야 하며 TDD "구성, 실행 및 어설션"패턴도 깨뜨립니다.
RSpec이 있는 VCR
VCR은 자체 구성을 위해 RSpec의 메타데이터를 사용하는 RSpec과의 통합을 제공합니다. 이 기능을 사용하는 데 필요한 구성은 here 입니다. 그러나 이 기사의 아이디어는 VCR을 세밀하게 제어하는 것이므로 사용하지 않겠습니다.
RSpec으로 VCR의 세밀한 제어
RSpec을 사용하여 VCR을 구성하여 세밀한 제어가 가능하도록 합시다. 구성은 다음 단계를 따릅니다.
# Configure it
VCR.configure do |config|
config.cassette_library_dir = "fixtures/vcr_cassettes"
config.hook_into :webmock
end
# Uses it
it 'does something' do
VCR.use_cassette('my_cassete') do
expect(do_request.body).to eql({success: true}.to_json)
end
end
shared_contexts
VCR 일반 구성
VCR 문서에 따라 일반적인 구성입니다.
require 'vcr'
VCR.configure do |c|
c.cassette_library_dir = 'spec/vcr_cassettes'
c.hook_into :webmock
end
필요하지 않은 사양에서 VCR 비활성화
꼭 필요한 것은 아니지만 좋은 습관이며 일부 HTTP 요청을 수행하거나 문제 없이 일반 모의 객체를 사용하는 경우 테스트가 실패하게 됩니다.
VCR에는 VCR 없이 실행할 코드 블록을 허용하는 메서드
turned_off
가 있습니다. 따라서 필요하지 않은 사양에서 VCR을 비활성화하려면 RSpec 후크around
를 사용합니다.# specs/spec_helper.rb
RSpec.configure do |config|
config.around do |example|
# Just disable the VCR, the configuration for its usage
# will be done in a shared_context
if example.metadata[:vcr]
example.run
else
VCR.turned_off { example.run }
end
end
end
VCR의 shared_context 구성
RSpec
shared_context
에서는 다음이 필요할 때만 VCR을 활성화할 수 있습니다.shared_context 'with vcr', vcr: true do
around do |example|
VCR.turn_on!
VCR.use_cassette(cassette_name) do
example.run
end
VCR.turn_off!
end
end
이를 통해
shared_context
다음과 같이 사용할 수 있으며 http가 기록됩니다.describe 'using vcr', vcr: true do
# Configure the cassete name
let(:cassete_name) { 'path/to/the/interaction' }
it 'record the http interaction' do
expect(do_request.body).to eql({ success: true }.to_json)
end
it 'reuse the same cassete here' do
expect(do_request.headers).to include('x-custom-header' => 'abc')
end
end
shared_context 개선
VCR
use_cassete
방법은 예를 들어 record_mode
와 같은 다른 많은 옵션을 허용합니다. shared_context
및 let
를 사용하면 개발 중인 새 상호 작용을 기록하도록 VCR을 구성할 수 있지만 CI에서 오류가 발생합니다. 예를 들면 다음과 같습니다.shared_context 'with vcr', vcr: true do
# Disable new records on CI. Most of the CI providers
# configure environment variable called CI.
let(:cassette_record) { ENV['CI'] ? :none : :new_episodes }
around do |example|
VCR.turn_on!
VCR.use_cassette(cassette_name, { record: cassette_record }) do
example.run
end
VCR.turn_off!
end
end
특정 shared_context 만들기
특정 사례에 대해 VCR을 구성하는 특정
shared_context
을 만들 수 있습니다. 예를 들어 일부 특정 요청에 대한 헤더를 무시할 필요가 없다고 가정합니다.shared_context 'with vcr matching headers', vcr_matching_headers: true do
around do |example|
VCR.turn_on!
VCR.use_cassette(cassette_name, { match_requests_on: [:method, :uri, :headers]}) do
example.run
end
VCR.turn_off!
end
end
결론
추가할 수 있는 VCR에는 더 많은 옵션이 있지만 예제는 테스트 세트에서 VCR을 제어하는 방법에 대한 아이디어를 제공합니다.
Reference
이 문제에 관하여(RSpec으로 VCR 구성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jorgefernando1/configure-vcr-with-rspec-48gh텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)