Frage

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:

  1. When a proxy is defined the request OpenURI makes actually uses the proxy info
  2. When a proxy isn't defined, a regular non-proxy connection is made

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
War es hilfreich?

Lösung

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top