【问题标题】:Testing before_create method in rspec and rails 3在 rspec 和 rails 3 中测试 before_create 方法
【发布时间】:2011-07-07 02:29:18
【问题描述】:

我查看了一些教程,我看到的都是关于如何测试 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)

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

这是我的模型:

用户.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 中进行了 put,它确实通过了那里,但之后它也通过了“真实的”api_call,这使得存根过时了。我该如何度过这个难关?

【问题讨论】:

    标签: activerecord callback rspec


    【解决方案1】:

    这里的一个好方法是将您的 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方法进行stub,返回一个固定的数据结构

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

    有关 any_instance 的更多信息,请查看this commit

    【讨论】:

    • 嗯,让我检查一下,但这看起来很有前途。只是一个问题,我已经有一个我保存为“sample-response.json”的夹具,我只是在 and_return 调用中执行 File.open(“sample-fixture.json”)吗?
    • 是的!如果您在 #generate_character 方法中解析 JSON,则可以从 and_return 调用中返回 JSON 夹具。
    • hmmm 想起来了,我实际上将 API 调用放在 generate_character 方法中,这样我只会调用一次而不是三次。假设我使用该 api 响应设置了 3 个属性。所以如果我把它放在一个单独的方法中,那将需要 3 次调用,而不是我把它放在一个变量中并在 generate_character 中调用它一次......对吗?
    • 我试着按照你说的做,但我的方法似乎没有被存根......我更新了我的问题以反映我所做的事情
    • 我注意到你正在存根 :api_response 并且输出数据的方法名称在示例中称为 :api_call 。是不是打错字了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2011-12-22
    • 1970-01-01
    • 2013-05-04
    • 2019-02-03
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多