在rspec和rails 3中测试before_create方法

时间:2011-07-07 02:29:19

标签: activerecord callback rspec

我看了一些tutes,我看到的只是关于如何测试before_create的旧帖子。此外,似乎他们只是测试before_create被称为即:。

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

我想实际测试我的方法是否有效,并且在创建记录后已经分配(并保存了变量)。

以下是我的模特:

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

和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

我想测试生成角色确实设置属性而不上线并调用API调用。这对rspec有可能吗?我有一个json响应的夹具,所以我希望我可以生成字符然后使用假响应进行测试。

这是我的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

每个角色的统计数据只打印出5个。我还在character.rb的generate_character方法中做了一个puts response,它仍然打印出“真正的”api调用。

我设法做了一个放入fake_response并且它确实经过那里,但它也经过了“真正的”api_call之后,这使得存根过时了。我如何度过难关?

1 个答案:

答案 0 :(得分:4)

这里的一个好方法是将api调用解压缩为自包含方法。像这样:

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

然后使用RSpec的any_instance来存根api_call方法以返回固定的数据结构

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

有关any_instance check this commit

的更多信息