You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写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 Page instead of triggering the Article's after_save callback. This means you're skipping the very logic you want to test!
  • self.id and self.url_part in your test context are nil—here, self refers to the RSpec example object, not an actual Article instance.
  • expect(page).to eq(true) is logically wrong: Page.create returns a Page instance, 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:

  1. Creating a corresponding Page when a new Article is saved
  2. Updating the Page's URL correctly when an existing Article is updated (handling both StaticPage and 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:17:39