gikian
gikian

Reputation: 25

How to write specs for this public method (using RSpec)?

I have written the following class:

# This class is responsible for getting the data to create the sitemap
class City
  attr_accessor :country_version, :directory, :country_host, :locale

  def initialize(country_version, directory, country_host,locale)
    @country_version = country_version
    @directory = directory
    @country_host = country_host
    @locale = locale
  end

  def get_data
    ::City.find_each(:conditions => {:country_version_id => @country_version.id}) do |city|
      I18n.locale=(@locale)
      yield entry(city)
    end
  end

  private

  def entry(city)
    {
      :loc => ActionController::Integration::Session.new.url_for(
                  :controller => 'cities', 
                  :action => 'show', 
                  :city_name => city.name, 
                  :host => @country_host.value),
      :changefreq => 0.8,
      :priority => 'monthly',
      :lastmod => city.updated_at
    }
  end
end 

I am using RSpec to write specs for this class. My specs so far cover the accessor methods and the constructor. I am lost however when it comes to the more complex method get_data. Can someone give me some hints how I can tackle the problem of writing a spec for that method?

Upvotes: 1

Views: 408

Answers (2)

ian
ian

Reputation: 12251

A simple test would surely be along the lines of:

  • Does it blow up on instantiation?
  • Does it return data when given good arguments?
  • Does it return what I expect (zero/nil/exception?) when given bad arguments or those that lead to no results?

Some code:

describe :City do
  let(:country_version) { 123412 }
  # other useful args here
  context "On instantiation" do
    context "Given valid arguments" do
      subject { City.new country_version, ...}
      it { should_not be_nil }
      it { should be_a_kind_of City }
    end
  end
  end
  context "Given a country version id" do
    context "that is valid" do
      context "and records exist for in the datastore"
        let(:city) { City.new country_version, ...}
        subject { city.get_data }
        it { should_not be_nil } 
        it { should be_a_kind_of... (Array, Hash?) }
        it { should include( ...? }
      end
    end
  end
end

Obviously, this won't work as I've no idea what should be going in and out, but it gives you something to be going on with, and it implies some of the missing specs too (like invalid arguments and so forth)

See https://www.relishapp.com/rspec/rspec-expectations for more.

Some of the comments here are right too, you probably will need mocks at some point, and you probably do need to refactor this method anyway, so posting to the code style forum might be an idea too.

Upvotes: 2

Paweł Obrok
Paweł Obrok

Reputation: 23164

This is very verbose, your only actual method here is get_data. You could use:

class City < Struct(:country_version, :directory, :country_host, :locale)
  ...
end

To get accessors, constructors, and a bit more for free, and not test those (see Struct)

Upvotes: 0

Related Questions