Как проверить метод обратного вызова модели самостоятельно?
У меня был метод в модели:
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
Тест прошел, но я беспокоюсь не о конкретном методе. Эффект будет смешанным с другими обратными вызовами, если будет добавлено больше.
Мой вопрос: есть ли какой-либо красивый способ проверить методы экземпляра модели независимо, что становится обратным вызовом?
Ответы
Ответ 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