Общие примеры RSpec — передача данных в общие спецификации

#ruby-on-rails #ruby #rspec

#ruby-on-rails #ruby #rspec

Вопрос:

Я пробовал несколько способов получения нужных мне данных в моих общих спецификациях, однако я всегда получаю неопределенные значения.

Я делаю что-то похожее на следующее:

 require 'spec_helper'

describe UserAnalyticsService do

  before(:each) { @user = FactoryGirl(:user) }

  let(:user_query) { UserAnalyticsQuery.build(@user) }
  let(:totals) { UserAnalyticsService.new(user_query) }

  it_should_behave_like "an array of hashes" # What I want
end
 

Я пробовал следующее:

Вложенный let()

 shared_examples "an array of hashes" do
  it { expect(array).to be_an_instance_of(Array) }
  it "each element should be an instance of Hash" do
    array.each { |element| expect(element).to be_an_instance_of(Hash) }
  end
end
 

И выполнение:

использование let()

 it_should_behave_like "an array of hashes" do
  let(:array) { totals.inactive_users }
end
 

использование переменной экземпляра

 before(:each) { @array = totals.inactive_users }
 

Затем

 it_should_behave_like "an array of hashes" do
  let(:array) { @array }
end
 

Параметры блока

 shared_examples "an array of hashes" do |array|
  it { expect(array).to be_an_instance_of(Array) }
  it "each element should be an instance of Hash" do
    array.each { |element| expect(element).to be_an_instance_of(Hash) }
  end
end
 

Затем

 it_should_behave_like "an array of hashes", @array
 

Все следующее приводит к nil исключениям указателей и неопределенным переменным.

Любые советы, предложения или рекомендации приветствуются, заранее спасибо.

Редактировать

Хорошо, итак, я углубился в let() изучение и понимаю, что данные, переданные в общий пример, должны существовать до транзакционного блока.

Я почти уверен, что это была моя проблема, поскольку я использовал before(:each) и let() для передачи данных, однако они оба не определены, пока мы не дойдем до группы примеров.

Ввод по-прежнему очень приветствуется, особенно в отношении альтернатив или перспектив, которые помогут перенести эти общие спецификации в общий пример.

Ответ №1:

Должен признать, я был смущен использованием rspec shared_examples и отказался от них в последний раз, когда пытался с ними работать, но ваш вопрос вдохновил меня на другой взгляд.

Удивительно, но на самом деле это оказалось очень просто и не заняло слишком много времени, чтобы выполнить некоторые пройденные тесты — я либо упускаю что-то фундаментальное в вашем вопросе, либо следующее должно дать вам некоторый намек на то, что вам нужно сделать.

Сами тесты должны быть понятными:

 require 'rails_helper'

RSpec.describe Array, type: :class do
  shared_examples 'an array of hashes' do
    it { expect(array).to be_an_instance_of(Array) }

    it 'each element should be an instance of Hash' do
      array.each { |element| expect(element).to be_an_instance_of(Hash) }
    end
  end

  describe 'with an array of hashes' do
    context 'with predefined array' do
      let(:hash) { Hash.new(name: 'hash', value: 'value') }
      let(:array) { [hash, hash, hash] }

      context 'without using shared examples' do
        it { expect(array).to be_an_instance_of(Array) }

        it 'each element should be an instance of Hash' do
          array.each { |element| expect(element).to be_an_instance_of(Hash) }
        end
      end

      context 'using shared examples' do
        it_should_behave_like 'an array of hashes'
      end
    end

    context 'when passing array to shared example' do
      let(:hash) { Hash.new(name: 'hash', value: 'value') }
      let(:myarray) { [hash, hash, hash] }

      it_should_behave_like 'an array of hashes' do
        let(:array) { myarray }
      end

      context 'with use of before(:each) block' do
        before(:each) do
          @myarray = myarray
        end

        it_should_behave_like 'an array of hashes' do
          let(:array) { @myarray }
        end
      end
    end
  end
end
 

Не должно быть причин, по которым следующее также не должно работать:

 it_should_behave_like 'an array of hashes' do
  let(:array) { totals.inactive_users }
end
 

Комментарии:

1. Привет, спасибо, что вернулись к этому! Теперь я понимаю, почему последний пример должен работать. Общий пример выполняется внутри транзакции, let(:array) вызывается внутри этой транзакции, затем let(:total) вызывается by let(:array) . Я не уверен, почему это не работало, но я помню, что это было не определено. Спасибо, что добавили еще один уровень понимания этой проблемы!