如何测试我的before_save回调是否正确

时间:2011-04-12 16:31:19

标签: ruby-on-rails ruby activerecord rspec

我的ActiveRecord模型有回调,如下所示:

  before_save :sync_to_external_apis

  def sync_to_external_apis                                                                                                 
    [user, assoc_user].each {|cuser|
      if cuser.google_refresh
        display_user = other_user(cuser.id)
        api = Google.new(:user => cuser)
        contact = api.sync_user(display_user)
      end
    }
  end

我想写一个rspec测试,测试调用save!在google_refresh为true时,在此模型的实例上会导致在新的Google实例上调用sync_user。我怎么能这样做?

3 个答案:

答案 0 :(得分:4)

it "should sync to external apis on save!" do
  model = Model.new
  model.expects(:sync_to_external_apis)
  model.save!
end

另外,在请求 - 响应周期期间请求不可靠的资源(如互联网)是一个坏主意。我建议改为创建一个后台工作。

答案 1 :(得分:0)

通常的测试方法是确保结果符合预期。由于您在这种情况下使用的API可能会使事情变得复杂。您可能会发现使用mocha创建一个模拟对象,您可以发送API调用,这样您就可以将Google类替换为可用于测试目的的一些东西。

更简单但更笨重的方法是使用“测试模式”开关:

def sync_to_external_apis
  [ user, assoc_user ].each do |cuser|
    if (Rails.env.test?)
      @synced_users ||= [ ]
      @synced_users << cuser
    else
      # ...
    end
  end
end

def did_sync_user?(cuser)
  @synced_users and @synced_users.include?(cuser)
end

这是一种简单的方法,但它不会验证您的API调用是否正确。

答案 2 :(得分:-1)

摩卡是要走的路。我不熟悉rspec,但这是你在测试单元中的表现方式:

def test_google_api_gets_called_for_user_and_accoc_user
    user = mock('User')                  # define a mock object and label it 'User'
    accoc_user = mock('AssocUser')       # define a mock object and label it 'AssocUser'

    # instantiate the model you're testing with the mock objects
    model = Model.new(user, assoc_user)

    # stub out the other_user method.  It will return cuser1 when the mock user is 
    # passed in and cuser2 when the mock assoc_user is passed in
    cuser1 = mock('Cuser1')
    cuser2 = mock('Cuser2')
    model.expects(:other_user).with(user).returns(cuser1)
    model.expects(:other_user).with(assoc_user).returns(cuser2)


    # set the expectations on the Google API
    api1 - mock('GoogleApiUser1')          # define a mock object and lable it 'GoogleApiUser1'
    api2 - mock('GoogleApiUser2')          # define a mock object and lable it 'GoogleApiUser2'

    # call new on Google passing in the mock  user and getting a mock Google api object back
    Google.expects(:new).with(:user => cuser1).returns(api1)
    api1.expects(:sync_user).with(cuser1)

    Google.expects(:new).with(:user => cuser2).returns(api2)
    api2.expects(:sync_user).with(cuser2)

    # now execute the code which should satisfy all the expectations above
    model.save!
end

上面看起来似乎很复杂,但是一旦你掌握了它,它就不是了。您正在测试当您调用save时,您的模型会执行它应该执行的操作,但您没有麻烦,或者没有真正与API通信,实例化数据库记录等的时间费用。