1

I've looked into some tutes and all I saw were old posts on how to test before_create. Also it seems like they're all just testing that before_create was called i.e.:

@user = User.new
@user.should_receive(:method_name_called_by_before_create)
@user.send(:before_create) (sometimes they just do @user.save)

I want to actually test that my method worked and that it had assigned(and saved the variables) after creating the record.

Here are my models:

user.rb

class User < ActiveRecord::Base
  has_one :character, :dependent => :destroy

  after_create :generate_character

  private
    def generate_character
      self.create_character(:name => "#{email}'s avatar")
    end
end

and character.rb

class Character < ActiveRecord::Base

  belongs_to :user

  before_create :generate_character

  private
    def generate_character
      response = api_call
      #API CALL HERE

      #set object attributes here
      self.stat1 = calculate_stat1(response) + 5
      self.stat2 = calculate_stat2(response) + 5
      self.stat3 = calculate_stat3(response) + 5            
    end

    def api_call
      return api_call_response
    end

end

I want to test that generate character indeed set the attributes without going online and calling the API call. Is this possible with rspec? I have a fixture of a json response so I was hoping I can stub out generate character and then use the fake response for testing.

Here's my character.spec:

describe Character do
  before(:each) do
    Character.any_instance.stub!(:api_call).and_return(fake_response.read)
    @user = Factory(:user)
    @character = @user.character
    puts  @character.inspect
end

def fake_response
  File.open("spec/fixtures/api_response.json")
end

It prints out only 5 for each of the character's stats. Also I did a puts response in the generate_character method in character.rb and it still prints out the "real" api call.

I managed to do a puts in fake_response and it does goes through there but it also goes through the "real" api_call after, which makes the stub obsolete. How do I get through this?

1 Answer 1

4

A good approach here is extracting your api call into a self contained method. Something like this:

class Character < ActiveRecord::Base
  belongs_to :user
  before_create :generate_character

  private
    def generate_character
      data = api_call

      #set object attributes from data
    end

    def api_call
      # returns a data structure
      # resulting from the call
    end
end

Then use RSpec's any_instance to stub the api_call method to return a fixed data structure

Character.any_instance.stub!(:api_call).and_return { {:id => 1, :attribute_one => "foo"} }
@user = User.create
@user.character.attribute_one.should == "foo"

for more info on any_instance check this commit

Sign up to request clarification or add additional context in comments.

5 Comments

hmm lemme check on that but that looks very promising man. just a question, i already have a fixture that i saved as "sample-response.json", do i just do a File.open( "sample-fixture.json" ) in my and_return call?
yes definitely! you could return the JSON fixture from the and_return call if you deal with parsing that JSON in the #generate_character method.
hmmm come to think of it, i actually put the API call in the generate_character method so that i'll only call it once as opposed to thrice. Let's say i set 3 attributes using that api response. so if i put it in a separate method, that will take 3 calls, instead of i put it the response in a variable and call it once in generate_character...right?
i tried to do what you said but it seems that my method isn't being stubbed...i updated my question to reflect what i have done
I noticed you are stubbing :api_response and the method name outputting the data is called :api_call in the example. Is that a typo?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.