I have the following method that is responsible for requesting a URL and returning it's Nokogiri::HTML
document. This method checks if a proxy is defined and if it does, it will call OpenURI
's open
with or without the proxy options.
Implementation
require 'open-uri'
require 'nokogiri'
class MyClass
attr_accessor :proxy
# ....
def self.page_content(url)
if MyClass.proxy
proxy_uri = URI.parse(MyClass.proxy)
Nokogiri::HTML(open(url, :proxy => proxy_uri)) # open provided by OpenURI
else
Nokogiri::HTML(open(url)) # open provided by OpenURI
end
end
end
I have no idea how I should write tests that prove the following:
Here's what I came up with as a start for the tests.
describe MyClass, :vcr do
describe '.proxy' do
it { should respond_to(:proxy) }
end
describe '.page_content' do
let(:url) { "https://google.com/" }
let(:page_content) { subject.page_content(url) }
it 'returns a Nokogiri::HTML::Document' do
page_content.should be_a(Nokogiri::HTML::Document)
end
# How do i test this method actually uses a proxy when it's set vs not set?
context 'when using a proxy' do
# ???
xit 'should set open-uri proxy properties' do
end
end
context 'when not using a proxy' do
# ???
xit 'should not set open-uri proxy properties' do
end
end
end
end
First of all, you need to arrange for the proxy
method to return a proxy in one test case and not in the other. If there is a "setter" method for proxy, you can use that, otherwise you can stub the proxy
method.
Then, at a minimum, you want to set an expectation on open
that it will be called with or without the :proxy
option, depending on which test it is. Beyond that, you have the choice of whether to stub and set expectations for the various other calls involved in the method, including URI.parse
and Nokogiri::HTML
.
See https://github.com/rspec/rspec-mocks for information on establishing your test doubles and setting expectations. Note in particular the and_call_original
option if you want to use a partial stubbing approach.
Update: Here's some code to get you started. This works for the non-proxy method. I've left the proxy case for you. Note also that this uses the "partial stubbing" approach, where you still end up calling the external gems.
require 'spec_helper'
describe MyClass do
describe '.proxy' do # NOTE: This test succeeds because of attr_accessor, but you're calling a MyClass.proxy (a class method) within your page_content method
it { should respond_to(:proxy) }
end
describe '.page_content' do
let(:url) { "https://google.com/" }
let(:page_content) { MyClass.page_content(url) } # NOTE: Changed to invoke class method
context 'when not using a proxy' do
before {allow(MyClass).to receive(:proxy).and_return(false)} # Stubbed for no-proxy case
it 'returns a Nokogiri::HTML::Document' do
page_content.should be_a(Nokogiri::HTML::Document)
end
it 'should not set open-uri proxy properties' do
expect(MyClass).to receive(:open).with(url).and_call_original # Stubbing open is tricky, see note afterwards
page_content
end
end
# How do i test this method actually uses a proxy when it's set vs not set?
context 'when using a proxy' do
# ???
xit 'should set open-uri proxy properties' do
end
end
end
end
Stubbing of open
is tricky. See How to rspec mock open-uri? for an explanation.