Rspec에서 모의를 사용하여 테스트를 작성하겠습니다.
18548 단어 RSpec
이 기사에서 쓰기
이 기사에서 쓰지 않는 것
제일 전하고 싶은 일
테스트하려는 코드
rake 작업입니다. 코드는 실제 코드에 비해 단순화되었습니다.
Amazon Product Advertising API 5.0을 요청하여 제품을 생성한다는 내용.
지금 현재 (2020/07) Ruby용 공식 SDK 없기 때문에,
htps : // 기주 b. 코 m / 하카넨 사리 / め 쿠 m
이번에는 vacuum이라는 gem을 사용하여 구현됩니다.
lib/tasks/item.rake
namespace :item do
desc 'amazon apiで取得した商品を登録する'
task insert_from_amazon_search_item: :environment do
# request作成
request = Vacuum.new(marketplace: 'JP',
access_key: 'xxxxxxxxxx',
secret_key: 'yyyyyyy',
partner_tag: 'hoge_fuga')
# search_items を呼び出す
response = request.search_items({
search_index: 'All',
market_place: 'www.amazon.co.jp',
resources: [
'ItemInfo.Title',
'Offers.Summaries.LowestPrice'
],
keywords: 'ねこまみれ'
})&.to_h
response['SearchResult']['Items'].each do |item|
new_price = item['Offers']['Summaries'].detect do |summary|
summary['Condition']['Value'] == 'New'
end
# itemの作成
Item.create name: item['ItemInfo']['Title']['DisplayValue'], price: new_price['LowestPrice']['Amount']
end
end
end
spec/lib/tasks/item_spec.rb
require 'rails_helper'
require 'rake'
RSpec.describe 'item:insert_from_amazon_search_item' do
before(:all) do
@rake = Rake::Application.new
Rake.application = @rake
Rake.application.rake_require 'tasks/item'
Rake::Task.define_task(:environment)
end
before(:each) do
@rake[task_name].reenable
end
context 'when valid response returns,' do
let(:task_name) { 'item:insert_from_amazon_search_item' }
it 'creates new item.' do
# ど、どうしたらいい・・・・・・
expect do
@rake[task_name].invoke
end.to change(Item, :count).by(1)
end
end
end
자신이 테스트를 작성하기가 어렵다고 느낀 부분
search_items
에서 item을 참조하는 데 사용 to_h
htps : // 기주 b. 이 m/하카넨사리/ゔぁくうm/bぉb/마s테 r/ぃb/ゔぁくうm/레 s폰세. rb#L44Array#to_h
에 정의되어 있는 메소드. 어떻게 테스트로 대답하도록 하면 좋을까? 어렵다고 느끼는 것은 코드를 쓰는 법이 이상하다는 것을 깨닫는다.
논리를 수정할 때 의식이 있음
Vacuum::Response
를 호출하는 부분의 로직은 class로 해, 그 안에서 각각의 외부에 의존한 메소드를 호출하게 한다 이것에 의해, 테스트에서는 mock를 사용해, 그 class의 인스턴스에 대해서 응답하는 값을 설정하기 쉬워졌다.
class는 어느 디렉토리에 넣어야 하는가.
Vacuum
와 같이, 외부 서비스에 관한 로직이었으므로, app/libs/amazon_product_api_caller.rb
이하에 작성했습니다.app/libs/amazon_product_api_caller.rb
class AmazonProductApiCaller
def initialize
@request = amazon_api_request
end
def search_items
@request.search_items({
search_index: 'All',
market_place: 'www.amazon.co.jp',
resources: [
'ItemInfo.Title',
'Offers.Summaries.LowestPrice'
],
keywords: 'ねこまみれ'
})&.to_h
end
private
def amazon_api_request
return Vacuum.new if Rails.env.test?
Vacuum.new(marketplace: 'JP',
access_key: 'xxxxxxxxxx',
secret_key: 'yyyyyyy',
partner_tag: 'hoge_fuga')
end
end
lib/tasks/item.rake
namespace :item do
desc 'amazon apiで取得した商品を登録する'
task insert_from_amazon_search_item: :environment do
# request作成
amazon_product_api_caller = AmazonProductApiCaller.new
# search_items を呼び出す
response = amazon_product_api_caller.search_items
response['SearchResult']['Items'].each do |item|
new_price = item['Offers']['Summaries'].detect do |summary|
summary['Condition']['Value'] == 'New'
end
# itemの作成
Item.create name: item['ItemInfo']['Title']['DisplayValue'], price: new_price['LowestPrice']['Amount']
end
end
end
이런 상태가 되면 드디어 테스트에 다시 한번 마주합니다.
참고로 해 주신 Qiita의 기사 감사합니다.
사용할 수 있는 RSpec 입문·그 3 「제로로부터 알 수 있는 모의(mock)를 사용한 테스트의 작성 방법」
spec/lib/tasks/item_spec.rb
require 'rails_helper'
require 'rake'
RSpec.describe 'item:insert_from_amazon_search_item' do
before(:all) do
@rake = Rake::Application.new
Rake.application = @rake
Rake.application.rake_require 'tasks/item'
Rake::Task.define_task(:environment)
end
before(:each) do
@rake[task_name].reenable
# 実際に返ってくるレスポンスと同じような値を用意する。
response_hashed = {
"SearchResult" => {
"Items" => [{...}]}
}
# AmazonApiに関するモックを用意。(外部との難しい部分をうけおってくれるモックになる。頼むぞ!
let(:amazon_api_double) { double('amazon api caller') }
# Vacuum.new に対しては、こちらで用意したモックを返すようにする
allow(Vacuum).to receive(:new).and_return(amazon_api_double)
# こちらで用意したモック(Vacuumのフリをするモック)に対してsearch_itemsを呼べるようにする。
allow(amazon_api_double).to receive(:search_items)
# AmazonProductApiCaller のインスタンスに対してsearch_itemsが呼ばれたら、テストで用意した値が返るようにする。
allow_any_instance_of(AmazonProductApiCaller).to receive(:search_items).and_return(response_hashed)
end
context 'when valid response returns,' do
let(:task_name) { 'item:insert_from_amazon_search_item' }
it 'creates new item.' do
expect do
@rake[task_name].invoke
end.to change(Item, :count).by(1)
end
end
end
이렇게 무사히 테스트를 쓸 수 있었습니다.
Reference
이 문제에 관하여(Rspec에서 모의를 사용하여 테스트를 작성하겠습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/xxl/items/704c60b508f6ccdc7d67텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)