Подтвердить что ты не робот

Rails rspec перед всеми vs перед каждым

contest_entry_spec.rb

    require 'spec_helper'

    describe ContestEntry do

      before(:all) do
        @admission=Factory(:project_admission)
        @project=Factory(:project_started, :project_type => @admission.project_type)
        @creative=Factory(:approved_creative, :creative_category => @admission.creative_category)
        @contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
      end

      context 'non-specific tests' do
        subject { @contest_entry }
        it { should belong_to(:owner).class_name('User') }
        it { should belong_to(:project) }
        it { should have_many(:entry_comments) }

        it { should validate_presence_of(:owner) }
        it { should validate_presence_of(:project) }
        it { should validate_presence_of(:entry_no) }
        it { should validate_presence_of(:title) }

      end
end

Когда я запускаю эти тесты, все это okey, но если я изменю до (: все) до (каждый), каждый тест будет сбой. Я не знаю, почему это происходит?

Это ошибка

 Failure/Error: @contest_entry=Factory(:contest_entry, :design_file_name => 'bla bla bla', :owner => @creative, :project => @project)
     ActiveRecord::RecordInvalid:
       Validation Failed: User is not allowed for this type of project
4b9b3361

Ответ 1

before(:all) запускает блок один раз до запуска всех примеров.

before(:each) запускает блок один раз перед каждым из ваших спецификаций в файле

before(:all) устанавливает переменные экземпляра @admission, @project, @creative, @contest_entry за один раз до запуска всех блоков it.

Однако :before(:each) сбрасывает переменные экземпляра в блоке before каждый раз, когда выполняется блок it.

Его тонкое различие, но важное

снова,

before(:all)
#before block is run
it { should belong_to(:owner).class_name('User') }
it { should belong_to(:project) }
it { should have_many(:entry_comments) }

it { should validate_presence_of(:owner) }
it { should validate_presence_of(:project) }
it { should validate_presence_of(:entry_no) }
it { should validate_presence_of(:title) }

before(:each)
# before block
it { should belong_to(:owner).class_name('User') }
# before block
it { should belong_to(:project) }
# before block
it { should have_many(:entry_comments) }
# before block

# before block
it { should validate_presence_of(:owner) }
# before block
it { should validate_presence_of(:project) }
# before block
it { should validate_presence_of(:entry_no) }
# before block
it { should validate_presence_of(:title) }

Ответ 2

Важная деталь before :all, что это не transactional БД. То есть, все в рамках before :all сохраняется в БД, и вы должны вручную разорвать метод after :all.

Подразумевается, что после завершения тестовых наборов изменения не возвращаются, готовые к последующим тестам. Это может привести к сложным ошибкам и проблемам с перекрестным загрязнением данных. Т.е., если выбрасывается исключение, обратный вызов after :all: не вызывается.

Тем не менее, before: each тем before: each является БД транзакций.

Быстрый тест для демонстрации:

1. Обрежьте нужную таблицу БД и попробуйте

  before :all do
    @user = Fabricate(:user, name: 'Yolo')
  end

2. Посмотрите базу данных, после чего модель останется неизменной !

after :all требуется. Однако, если в вашем тесте возникает исключение, этот обратный вызов не произойдет, поскольку поток был прерван. База данных останется в неизвестном состоянии, что может быть особенно проблематичным в средах CI/CD и автоматическом тестировании.

3. Теперь попробуйте это,

  before :each do
    @user = Fabricate(:user, name: 'Yolo')
  end

4. Теперь база данных остается без данных после завершения набора тестов. Гораздо лучше и оставляет нам стабильное состояние после выполнения тестов.

Короче говоря, before :each, вероятно, то, что вы хотите. Ваши тесты будут работать немного медленнее, но это того стоит.

Подробности здесь: https://relishapp.com/rspec/rspec-rails/docs/transactions См.: Data created in before(:all) are not rolled back

Надеюсь, что это поможет другому усталому путешественнику.

Ответ 3

before(:all), который гарантирует, что образец пользователей создается один раз, перед всеми тестами в блоке. Это оптимизация скорости.

Ответ 4

Следует отметить, что по умолчанию перед использованием before (: each), а также before (: all) экземпляр контроллера не установлен, поэтому методы контроллера, такие как request, не используются.