Как я могу протестировать методы в абстрактном базовом классе ApplicationRecord?

Я не нашел хорошего способа протестировать методы ApplicationRecord.

Скажем, у меня есть простой метод с именем one:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def one
    1
  end
end

И я хочу это проверить:

describe ApplicationRecord do
  let(:it) { described_class.new }

  it 'works' do
    expect(it.one).to eq 1
  end
end

Неудивительно, что это умирает с NotImplementedError: ApplicationRecord is an abstract class and cannot be instantiated.

Поэтому я попробовал предложение анонимного класса в Тестирование абстрактных классов в Rspec:

let(:it) { Class.new(described_class).new }

И это умирает с TypeError: no implicit conversion of nil into String, предположительно потому, что имя таблицы записи равно нулю.

Может ли кто-нибудь предложить хороший и простой способ протестировать методы ApplicationRecord? Надеюсь, что тот, который не вводит зависимости от других классов в моем приложении и не подключается к внутренним компонентам ActiveRecord?


person bronson    schedule 12.02.2016    source источник


Ответы (3)


Это сработало для меня в наших тестах:

class TestClass < ApplicationRecord
  def self.load_schema!
    @columns_hash = {}
  end
end

describe ApplicationRecord do
  let(:record) { TestClass.new }

  describe "#saved_new_record?" do
    subject { record.saved_new_record? }

    before { allow(record).to receive(:saved_change_to_id?).and_return(id_changed) }

    context "saved_change_to_id? = true" do
      let(:id_changed) { true }

      it { is_expected.to be true }
    end

    context "saved_change_to_id? = false" do
      let(:id_changed) { false }

      it { is_expected.to be false }
    end
  end
end

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

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

Я предпочитаю это гораздо больше, чем наличие другого модуля только для тестирования.

person ozzyaaron    schedule 26.01.2018

Я бы предложил извлечь эти методы в модуль (проблема) и оставить ApplicationRecord в покое.

module SomeCommonModelMethods
  extend ActiveSupport::Concern

  def one
    1
  end
end

class ApplicationRecord < ActiveRecord::Base
  include SomeCommonModelMethods
  self.abstract_class = true
end

describe SomeCommonModelMethods do
  let(:it) { Class.new { include SomeCommonModelMethods }.new } } 

  it 'works' do
    expect(it.one).to eq 1
  end
end
person Oleg Antonyan    schedule 13.02.2016
comment
Да! Лично я избегаю опасений (думаю, по этому поводу есть хорошие дебаты). Но я согласен держаться подальше от abstract_class в ActiveRecord. - person jvillian; 15.02.2016
comment
Создание файла проблемы для однострочной функции? Такое ощущение, что исходный код моего приложения искажается, чтобы компенсировать ограничение языка / библиотеки. Я все еще надеюсь, что кто-то может подсказать, как протестировать сам класс ApplicationRecord, но спасибо за очень хорошо написанное предложение! - person bronson; 17.02.2016
comment
ApplicationRecord - это стандарт в Rails 5. Зачем кому-то этого избегать? - person armchairdj; 20.04.2018

Если вы используете Rspec, вы можете создать общий пример , а затем вызовите его из спецификации каждой модели, унаследованной от ApplicationRecord. Недостатком этого будет тестирование всего этого поведения на каждой модели, но накладные расходы должны быть довольно низкими, если вы не запихиваете много общего поведения в ApplicationRecord.

person armchairdj    schedule 19.04.2018