如何编写Rspec测试用例验证Article模型的after_save回调?
Hey there! Let's break down what's wrong with your current test and fix it properly—because right now, you're not actually testing the after_save callback you care about.
What's Wrong With Your Current Test
Your existing test has a few critical issues:
- You're directly creating a
Pageinstead of triggering theArticle'safter_savecallback. This means you're skipping the very logic you want to test! self.idandself.url_partin your test context arenil—here,selfrefers to the RSpec example object, not an actualArticleinstance.expect(page).to eq(true)is logically wrong:Page.createreturns aPageinstance, not a boolean. You should check if the page was persisted instead.
The Correct Approach to Testing the Callback
We need to test the two core behaviors of your callback:
- Creating a corresponding
Pagewhen a newArticleis saved - Updating the
Page's URL correctly when an existingArticleis updated (handling bothStaticPageand regular article types)
Here's the revised article_spec.rb that properly tests these scenarios:
require 'rails_helper' RSpec.describe Article, type: :model do # Assume you have a Site factory; if not, replace with manual record creation let(:test_site) { create(:site) } let(:static_article) { build(:article, article_type: 'StaticPage', url_part: 'about-our-team', data_proxy_id: test_site.data_proxy_id) } let(:regular_article) { build(:article, article_type: 'Regular', url: '/tech/2024-update', data_proxy_id: test_site.data_proxy_id) } context 'when using the after_save callback (article_page_create)' do it 'creates a static page for a new StaticPage-type article' do # Verify page count increases by 1 when saving the article expect { static_article.save }.to change(Page, :count).by(1) # Fetch the created page and validate its attributes created_page = Page.find_by(entity_id: static_article.id) expect(created_page.page_type).to eq('static_page') expect(created_page.url).to eq("/static/#{static_article.url_part}") end it 'creates an article page for a new regular article' do expect { regular_article.save }.to change(Page, :count).by(1) created_page = Page.find_by(entity_id: regular_article.id) expect(created_page.page_type).to eq('article_page') expect(created_page.url).to eq(regular_article.url) end it 'updates the URL when modifying an existing regular article' do regular_article.save existing_page = Page.find_by(entity_id: regular_article.id) # Update the article's URL and refresh the page record regular_article.update(url: '/tech/2024-update-revised') existing_page.reload expect(existing_page.url).to eq('/tech/2024-update-revised') end it 'updates the static URL when modifying an existing StaticPage article' do static_article.save existing_page = Page.find_by(entity_id: static_article.id) static_article.update(url_part: 'contact-info') existing_page.reload expect(existing_page.url).to eq('/static/contact-info') end it 'does not create a duplicate page when saving an existing article' do static_article.save initial_page_count = Page.count # Update an attribute that doesn't affect the page URL static_article.update(title: 'Updated Team Page') # Confirm page count stays unchanged expect(Page.count).to eq(initial_page_count) end end # Bonus: Test the private callback method directly for edge cases context 'testing the article_page_create method directly' do it 'updates an existing static page correctly' do static_article.save existing_page = Page.find_by(entity_id: static_article.id) static_article.url_part = 'new-static-path' # Call the private method directly using send static_article.send(:article_page_create) existing_page.reload expect(existing_page.url).to eq('/static/new-static-path') end end end
Quick Tips for Improvement
- Use FactoryBot to create test instances—it makes your tests cleaner and more maintainable than manually building records every time.
- Testing the private callback method directly (like the bonus test above) lets you isolate and verify edge cases without relying on the full save lifecycle.
内容的提问来源于stack exchange,提问作者user3576036
相关产品推荐
相关产品推荐

