Rails fragment cache testing with RSpec

前端 未结 3 473
生来不讨喜
生来不讨喜 2021-02-04 15:22

I feel like this is a not-so-much documented topic, at least I\'ve had a lot of trouble finding our about the best practices here.

I\'m fragment caching in the view usin

相关标签:
3条回答
  • 2021-02-04 15:32

    I use view specs to test cache expiration in views:

    describe Expire::Employee, type: :view, caching: true do
    
      def hour_ago
        Timecop.travel(1.hour.ago) { yield }
      end
    
      def text_of(css, _in:)
        Nokogiri::HTML(_in).css(css).text
      end
    
      let(:employee) { hour_ago { create :employee } }
    
      def render_employees
        assign(:employees, [employee.reload])
        render(template: 'employees/index.html.erb')
      end
      alias_method :employees_list, :render_employees
    
      context "when an employee's position gets changed" do
        let(:position) { create :position, employee: employee }
        before { hour_ago { position.update!(name: 'Old name') } }
        let(:update_position) { position.update!(name: 'New name') }
    
        it "should expire the employee's cache" do
          expect { update_position }
            .to change { text_of('.positions', _in: employees_list) }
            .from(/Old name/).to(/New name/)
        end
      end
    
      # similar spec case for home base assignment
    end
    

    where

    • Timecop gem is used to travel in time to make sure that cache key timestamps are different for different cache versions of employee
    • Nokogiri gem is used to extract employee position's text from the rendered view

    Note that I tagged this spec with caching: true. It enables caching before each test case and disables after it:

    config.before(:each, caching: true) do
      controller.perform_caching = true
    end
    config.after(:each, caching: true) do
      controller.perform_caching = false
    end
    

    And you might want to add an example that checks that an employee is being actually cached

    describe Expire::Employee, type: :view, caching: true do
      context 'with an uncached employee' do
        it 'should cache the employee' do
          expect_any_instance_of(Employee)
            .to receive(:current_positions).once
    
          2.times { render_employees }
        end
      end
    
      # other spec cases
    end
    
    0 讨论(0)
  • 2021-02-04 15:45

    Let me first say that in this answer, you may get more sympathy then fact. I've been struggling with these same issues. While I was able to get reproducible results for a particular test, I found that the results varied according to whether or not I ran one versus multiple specs, and within or without spork. Sigh.

    In the end, I found that 99.9% of my issues disappeared if I simply enabled caching in my test.rb file. That might sound odd, but after some thought it was "correct" for my application. The great majority of my tests are not at the view/request layer, and for the few that are, doesn't it make sense to test under the same configurations that the user views?

    While I was wrestling with this, I wrote a blog post that contains some useful test helpers for testing caching. You might find it useful.

    0 讨论(0)
  • 2021-02-04 15:48

    Here is what I've used in my specs with caching enabled in my config/environments/test.rb

    require 'spec_helper'
    include ActionController::Caching::Fragments
    
    describe 'something/index.html.erb' do
      before(:each) do 
        Rails.cache.clear
        render
      end
      it 'should cache my fragment example' do
        cached_fragment = Rails.cache.read(fragment_cache_key(['x', 'y', 'z']))
        cached_fragment.should have_selector("h1")
      end
    end
    
    0 讨论(0)
提交回复
热议问题