Witam!
Mam pytanie w jaki sposób testujecie serwis który wykorzystuje api.
Mam serwis który wykorzystuje do wyszukiwania informacji o filmach. Wygląda on tak:
class OmdbService
include HTTParty
base_uri 'www.omdbapi.com'
def initialize(title, year)
@options = { query: { t: title, y: year, apikey: Rails.application.credentials.dig(:omdb, :apikey) } }
end
def search
self.class.get('', @options)
rescue HTTParty::Error => e
inspect_errors(e)
rescue StandardError => e
inspect_errors(e)
nil
end
def search_result
search || NullOmdb.new
end
private
def inspect_errors(error)
logger.error error
end
def logger
@logger ||= ::Logger.new("log/#{Rails.env}.log")
end
end
Testuję tak:
require 'rails_helper'
RSpec.describe OmdbService do
it 'fetches Title from api service' do
expect(OmdbService.new('Terminator', '2019').search.parsed_response['Title']).to eq('Terminator: Dark Fate')
end
it 'fetches null object' do
end
end
Pytanie - w jaki sposób można testować taki serwis? Jak np testować sytuację gdy nie mamy połączenia z internetem lub jeśli jest null?
Jeśli dobrze zrozumiałem Twoje pytanie to nasuwa mi się pomysł aby odłączyć sobie internet i nagrać ten request używając VCR, ale nie jestem pewny co z tego wyjdzie :P.
Witaj @fizzlebubble nie dokładnie o to mi chodziło. Sorry źle się wyraziłem. Jeśli odłączę internet przed nagraniem VCR to raczej nic z tego nie wyjdzie. Zresztą jak @soso zaznaczył jeśli nie ma internetu to nic nie będzie działać. Chodziło mi o to jak zachowa się serwis gdy np przestanie działać api lub nie będzie dostępny. W jaki sposób to można testować w rspec. Np jeśli zwróci pusty str ‘’
Gem VCR jest trudny do utrzymania w przypadku dużych projektów. Ogólnie polecam używać w szczególnej ostateczności. Testy powinny być wyizolowane. To co zaprezentowałeś mógłbyś zamockować w taki sposób:
subject(:omdb_service) { described_class.new('Terminator', '2019') }
let(:omdb_url) { "https://www.omdbapi.com" }
let(:omdb_response) { instance_double(HTTParty::Response, body: omdb_response_body) }
let(:omdb_response_body) { 'Terminator: Dark Fate' }
before do
allow(HTTParty).to receive(:get).and_return(omdb_response)
end
it 'fetches the titles from Omdb service' do
expect(HTTParty).to have_received(:get).with(omdb_url)
end
it 'fetches Title from api service' do
expect(omdb_service.search.parsed_response['Title']).to eq('Terminator: Dark Fate')
end
Dla nullObject zrobiłbym oddzielny context i musi być let(:omdb_response_body) { nil }
Jeżeli wkradł się jakiś błąd to przepraszam, ale nie sprawdzałem tego kodu tylko tak na kolanie wykrzesałem. Myślę, że tędy Twoja droga jest