Тестирование модели Rails в Spec, как создавать эффективные примеры? - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь протестировать свои модели в Rails, используя Rspec и FactoryBot.Я использую let!:

let!(:account1) { create(:account, :year) }
let!(:account2) { create(:account, :three_months) }
let!(:account3) { create(:account, :month) }
let!(:account4) { create(:account, :day) }

Я проверяю, возвращают ли мои области действия правильный массив записей.Я предполагаю, что также должны быть некоторые «плохие данные», чтобы проверить, не возвращает ли область действия то, что не должно.Например:

  describe ".seen_last_two_months" do
    subject { Account.seen_last_two_months.to_a }
    it { is_expected.to eq([account3, account4]) }
  end

Кажется, что при увеличении количества тестов скорость значительно падает.Кажется, что каждый тест, который вызывает let!, попадает в базу данных, создавая новую запись.

  1. Это способ, которым я настраиваю свои тесты правильно, поэтому я должен также тестировать для записей, которые не являютсяожидается, что запрос будет возвращен?
  2. Есть ли способ вызвать создание записей только один раз?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Вы можете создать все учетные записи один раз и протестировать на них все свои возможности.Просто переместите все под блок it, примерно так:

context "scopes" do
  it 'selects accounts correctly' do
    let!(:account1) { create(:account, :year) }
    let!(:account2) { create(:account, :three_months) }
    let!(:account3) { create(:account, :month) }
    let!(:account4) { create(:account, :day) }

    expect(Account.seen_last_two_months.to_a).to eq([account3, account4])
    expect(Account.another_scope.to_a).to eq([account1, account2])
    expect(Account.one_more_scope.to_a).to eq([account2])
  end
end

Но этот вид спецификаций сложнее поддерживать, вам нужно указать много разных атрибутов в ваших экземплярах, чтобы проверить все области.Я использую этот способ только для аналогичных областей, например областей по статусу («активный», «неактивный», «заархивированный»).

btw: всегда полезно давать более описательные имена, например

let!(:year_ago) { create(:account, :year) }
0 голосов
/ 18 мая 2018
  1. Правильно ли настроен мой тест, поэтому я должен также проверять записи, которые не должны быть возвращены запросом?

Да, просто вы должны.

Есть ли способ вызвать создание записей только один раз?

Да, вам нужно, чтобы эти записи были созданы для проверки определенной области.Таким образом, они должны быть вызваны только для этого конкретного теста.Вы можете переместить их в блок describe, относящийся к области проверки, и тогда они не будут вызваны для других тестов.

# Keep this one without `!`, so it will be called (in other tests), if and when needed
let(:account1) { create(:account, :year) }

describe ".seen_last_two_months" do
  let!(:account1) { create(:account, :year) }
  let!(:account2) { create(:account, :three_months) }
  let!(:account3) { create(:account, :month) }
  let!(:account4) { create(:account, :day) }
  subject { Account.seen_last_two_months.to_a }
  it { is_expected.to eq([account3, account4]) }
end

Обновление

Если выЕсли вы хотите создать записи только один раз для всех тестов, используйте before(:all).Похоже, вызов let определенных переменных внутри блока before(:all) - плохая идея, вместо этого используйте переменные экземпляра:

before(:all) do
  @account1 = create(:account, :year)
  @account2 = create(:account, :three_months)
  @account3 = create(:account, :month)
  @account4 = create(:account, :day)
end

describe ".seen_last_two_months" do
  subject { Account.seen_last_two_months.to_a }
  it { is_expected.to eq([@account3, @account4]) }
end

Замените все вхождения account* на @account* в ваших тестах.

Помните, что изменения, сделанные любым тестом в объекте, также будут отражены в следующих тестах.

...