0

Using Rspec, I am writing unit tests for @survey.description:

class Survey < ActiveRecord::Base
  def description
    if self.question.try(:description).present? && self.selected_input.present?
      return self.question.try(:description).gsub("{{product-name}}", self.selected_input.name)
    else
      return self.question.try(:description)
    end
  end    
  def selected_input
    @matches = Input.all.select{|input| self.goods.to_a.matches(input.goods) && self.industries.to_a.matches(input.industries) && self.markets.to_a.matches(input.markets)}
    @selection = @matches.select{|input| input.in_stock(self.competitor) == true}
    if @selection.empty? || @selection.count < self.iteration || @selection[self.iteration-1].try(:name).nil?
      return false
    else
      return @selection[self.iteration-1]
    end
  end    
end

At a minimum, I'd like to write a test case for when @survey.selected_input.present? is true and one for when it is false.

But I don't want to write line upon line of code creating an @input, setting other values elsewhere to ensure the @input is selected for the @survey, etc etc, just to set @survey.selected_input.present? to true. Is there some way I can do something like:

describe "description" do
  it "should do something when there is a selected input" do
      just_pretend_that @survey.selected_input = "apples"
      @survey.description.should == "How's them apples?"
  end
end

I've tagged this post mocking and stubbing as I've never consciously used either technique but I think one of them may hold the answer.

steven_noble
  • 4,133
  • 10
  • 44
  • 77

1 Answers1

0

In general it's not a good idea to stub methods for the object under test. Though, since you asked about the syntax, what you are looking for is RSpec Mocks:

describe Survey do
  subject(:survey) { Survey.new(...) }

  context 'requesting the description' do
    it 'contains product name when it has input' do
      survey.stub(selected_input: 'apples')
      expect(survey.description).to eq "How's them apples?"
    end
  end
end
Aaron K
  • 6,901
  • 3
  • 34
  • 29
  • @steven_noble It makes your test brittle. Due to the fact that you're binding your test to the implementation. It's fine to stub interactions with other objects (which is a calculated trade off based on how stable the other object's API is). You don't care how the object under test delegates internally, just how it behaves based on inputs and outputs. Checkout Sandi Metz's book "Practical Object Oriented Design in Ruby" and https://www.youtube.com/watch?v=URSWYvyc42M – Aaron K Jun 17 '13 at 02:13