В комментариях к посту о дублерах, стабах и моках Макс Прокопьев упомянул instance_double, секретную технику старших разработчиков. О ней и поговорим. Коротко, по делу и с примерами.
Ситуация
Возьмем пример с Notifications:
class Notifications
  def as_json
    # Загружаем и отдаем последние новости
    # и уведомления с серверов Юрия Лозы по ХТТП
  end
end
class NotificationsController
  def index
    # Оборачиваем уведомления в ключ 'data'
    render json: { data: notifications.as_json }
  end
  def notifications
    Notifications.new
  end
end
Чтобы не обращаться к серверам Лозы в тестах, используем дублера:
describe "NotificationsController#index" do
  let(:notifications) do
    double(:datasource, as_json: { notifications: [] })
  end
  before do
    allow(Notifications)
      .to receive(:new)
      .and_return(notifications)
  end
  it "wraps notifications in 'data' key" do
    get :index, format: :json
    expect(json_response["data"].keys)
      .to have_key "notifications"
  end
end
Что произойдет, если мы переименуем Notifications#as_json в Notifications#to_json? Ничего. Мы останемся наедине с зеленым тестом, проверяющим бесполезного дублера.
  
  
  instance_double
Чтобы не попадать в такую дебильную ситуацию, используйте instance_double:
describe 'NotificationsController#index' do
  let(:notifications) do
    instance_double(Datasource, as_json: { notifications: [] })
  end
  # ...
end
Такой дублер проверит свой интерфейс. Если метода нет или у него другие аргументы — красный тест.
Чтобы так же проверять моки и стабы, убедитесь, что verify_partial_doubles включен в spec_helper.rb.
Внимательный читатель со звездочкой наверняка заметил, что одного instance_double мало. Все верно. В RSpec есть похожие дублеры для классов, модулей и объектов: object_double и class_double.

    
Top comments (1)
Очень хороший метод :)