bonhoffer
bonhoffer

Reputation: 1473

Rails test involving an object that requires an api update

I am trying to get a Bill object to perform tests on. This is a US congress bill, which I have in xml via rsync on a data directory. My code takes in the name of the bill, say "h1.xml", parses the xml and then gets the full text of the bill from www.govtrack.us. So, in my main app, to create a bill

  def self.update_from_directory
    Dir.glob("#{Rails.root}/data/bills/small_set/*.xml").each do |bill_path|
      bill_name = bill_path.match(/.*\/(.*).xml$/)[1]
      b = Bill.find_or_create_by(:govtrack_name => bill_name)
      b.update_bill
      b.save!
    end
  end
def update_bill
    file_data = File.new("#{Rails.root}/data/bills/#{self.govtrack_name}.xml", 'r')
    bill = Feedzirra::Parser::GovTrackBill.parse(file_data)
    if bill && (self.introduced_date.nil? || (bill.introduced_date.to_date > self.introduced_date))

      self.congress = bill.congress
      self.bill_type = bill.bill_type
      self.bill_number = bill.bill_number
      ... and so on . . . until:
      get_bill_text 
  def get_bill_text
      bill_object = HTTParty.get("#{GOVTRACK_URL}data/us/bills.text/#{self.congress.to_s}/#{self.bill_type}/#{self.bill_type + self.bill_number.to_s}.html")
      self.bill_html = bill_object.response.body
      self.text_updated_on = Date.today
      Rails.logger.info "Updated Bill Text for #{self.ident}"
  end

My goal is very simple, I want to mock a whole bill for a test:

    def setup
       @my_test_bill = Bill.new(:govtrack_id => "h1")
       @my_test_bill.update_bill
    end

I am trying to get webmock and vcr working, but all the examples I can find, provide a way to mock a specific call and I don't want to have to retype a whole new update_bill method.

Any thoughts greatly appreciated.

Tim

Upvotes: 0

Views: 182

Answers (1)

Matt Lightner
Matt Lightner

Reputation: 26

Consider changing your update_bill method to:

def update_bill
  file_data = File.new("#{Rails.root}/data/bills/#{self.govtrack_name}.xml", 'r')
  bill = Feedzirra::Parser::GovTrackBill.parse(file_data)
  if bill && (self.introduced_date.nil? || (bill.introduced_date.to_date > self.introduced_date))

  self.congress = bill.congress
  self.bill_type = bill.bill_type
  self.bill_number = bill.bill_number

  # Yield to a block that can perform arbitrary calls on this bill
  if block_given?
    yield(self)
  end

  # Fill bill text if empty
  if bill_html.blank? && text_updated_on.blank?
    get_bill_text
  end
end

Then change your setup method to:

def setup
   @my_test_bill = Bill.new(:govtrack_id => "h1")
   @my_test_bill.update_bill do |bill|
     bill.text_updated_on = Date.today
     bill.bill_html = "The mock bill contents"
   end
end

That may not be exactly the solution, but this kind of approach--passing the receiver back to a block given to the method, allows you to modify the exact behavior of a given method at runtime.

Upvotes: 1

Related Questions