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

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

У меня был метод в модели:

class Article < ActiveRecord::Base
  def do_something
  end
end

У меня также был unit test для этого метода:

# spec/models/article_spec.rb
describe "#do_something" do
  @article = FactoryGirl.create(:article)
  it "should work as expected" do
    @article.do_something
    expect(@article).to have_something
  end
  # ...several other examples for different cases
end

Все было в порядке, пока я не нашел лучше переместить этот метод в обратный вызов after_save:

class Article < ActiveRecord::Base
  after_save :do_something

  def do_something
  end
end

Теперь все мои тесты об этом методе сломаны. Я должен исправить это:

  • Не более конкретный вызов do_something, потому что create или save также вызовет этот метод, или я встречу повторяющиеся действия db.
  • Измените create на build
  • Test reply_to
  • Используйте общий model.save вместо индивидуального вызова метода model.do_something

    describe "#do_something" do
      @article = FactoryGirl.build(:article)
      it "should work as expected" do
        expect{@article.save}.not_to raise_error
        expect(@article).to have_something
        expect(@article).to respond_to(:do_something)
      end
    end
    

Тест прошел, но я беспокоюсь не о конкретном методе. Эффект будет смешанным с другими обратными вызовами, если будет добавлено больше.

Мой вопрос: есть ли какой-либо красивый способ проверить методы экземпляра модели независимо, что становится обратным вызовом?

4b9b3361

Ответ 1

Обратное и обратное поведение - независимые тесты. Если вы хотите проверить обратный вызов after_save, вам нужно подумать об этом как о двух вещах:

  • Выполняется ли обратный вызов для правильных событий?
  • Является ли вызываемая функция правильной?

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

class Article < ActiveRecord::Base
  after_save    :do_something
  after_destroy :do_something_else
  ...
end

it "triggers do_something on save" do
  expect(@article).to receive(:do_something)
  @article.save
end

it "triggers do_something_else on destroy" do
  expect(@article).to receive(:do_something_else)
  @article.destroy
end

it "#do_something should work as expected" do
  # Actual tests for do_something method
end

Отменяет ваши обратные вызовы от поведения. Например, вы можете вызвать один и тот же метод обратного вызова article.do_something, когда обновляется какой-либо другой связанный объект, например user.before_save { user.article.do_something }. Это будет соответствовать всем этим.

Итак, продолжайте проверять свои методы как обычно. Беспокоитесь о обратных вызовах отдельно.

Изменить: опечатки и возможные заблуждения Изменить: изменить "сделать что-нибудь", чтобы "вызвать что-то"

Ответ 2

Вы можете использовать shoulda-callback-matchers для проверки существования ваших обратных вызовов без их вызова.

describe Article do
  it { should callback(:do_something).after(:save) }
end

Если вы также хотите проверить поведение обратного вызова:

describe Article do
  ...

  describe "#do_something" do
    it "gives the article something" do
      @article.save
      expect(@article).to have_something
    end
  end
end

Ответ 3

Это скорее комментарий, чем ответ, но я поставил его здесь для выделения синтаксиса...

Мне нужен способ пропустить обратные вызовы в моих тестах, вот что я сделал. (Это может помочь с нарушением тестов.)

class Article < ActiveRecord::Base
  attr_accessor :save_without_callbacks
  after_save :do_something

  def do_something_in_db
    unless self.save_without_callbacks
      # do something here
    end
  end
end

# spec/models/article_spec.rb
describe Article do
  context "after_save callback" do
    [true,false].each do |save_without_callbacks|
      context "with#{save_without_callbacks ? 'out' : nil} callbacks" do
        let(:article) do
          a = FactoryGirl.build(:article)
          a.save_without_callbacks = save_without_callbacks
        end
        it do
          if save_without_callbacks
            # do something in db
          else
            # don't do something in db
          end
        end
      end
    end
  end
end

Ответ 4

describe "#do_something" do

 it "gives the article something" do

  @article = FactoryGirl.build(:article)

   expect(@article).to have_something

 @article.save
end

end