Тестирование метода before_create в rspec и rails 3 - PullRequest
1 голос
/ 07 июля 2011

Я просмотрел несколько бестселлеров и увидел только старые посты о том, как тестировать before_create. Также кажется, что они все просто проверяют, что before_create называлось i.e.:

@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, поэтому я надеялся, что смогу отключить создание символа и затем использовать поддельный ответ для тестирования.

Вот мой персонаж. 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 для каждой характеристики персонажа. Кроме того, я сделал puts response в методе generate_character в character.rb, и он все еще выводит «настоящий» вызов API.

Мне удалось сделать путы в fake_response, и он проходит через него, но также проходит через «настоящий» api_call, что делает заглушку устаревшей. Как мне пройти через это?

1 Ответ

4 голосов
/ 07 июля 2011

Хороший подход заключается в извлечении вашего вызова 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 this commit

...