Optionally testing caching in Rails 3 functional t

2019-02-03 04:20发布

Generally, I want my functional tests to not perform action caching. Rails seems to be on my side, defaulting to config.action_controller.perform_caching = false in environment/test.rb. This leads to normal functional tests not testing the caching.

So how do I test caching in Rails 3.

The solutions proposed in this thread seem rather hacky or taylored towards Rails 2: How to enable page caching in a functional test in rails?

I want to do something like:

test "caching of index method" do
  with_caching do
    get :index
    assert_template 'index'
    get :index
    assert_template ''
  end
end

Maybe there is also a better way of testing that the cache was hit?

5条回答
forever°为你锁心
2楼-- · 2019-02-03 04:41

A solution for rspec:

Add an around block with a custom metadata key to your configuration.

RSpec.configure do |config|
  config.around(:each, :caching) do |example|
    caching = ActionController::Base.perform_caching
    ActionController::Base.perform_caching = example.metadata[:caching]
    example.run
    Rails.cache.clear
    ActionController::Base.perform_caching = caching
  end
end

Add the metadata key when caching is needed.

describe "visit the homepage", :caching => true do
  # test cached stuff
end
查看更多
叛逆
3楼-- · 2019-02-03 04:46

Here is my current solution to the problem: In environment/test.rb I set

config.action_controller.perform_caching = true

Also, I am monkey patching Test::Unit::TestCase as follows:

class Test::Unit::TestCase
  def setup_with_disable_caching
    setup_without_disable_caching
    disable_caching
  end
  alias_method_chain :setup, :disable_caching

  def disable_caching
    ActionController::Base.perform_caching = false
  end

  def enable_caching(&blk)
    ActionController::Base.perform_caching = true
    if blk
      yield
      disable_caching
    end
  end
end

This allows me to write the following tests:

test "info about caching (with caching)" do
  enable_caching do
    get :about, :locale => :en
    assert_template 'about'
    get :about, :locale => :en
    assert_template nil
  end
end

test "info about caching (without caching)" do
  get :about, :locale => :en
  assert_template 'about'
  get :about, :locale => :en
  assert_template 'about'
end

It's not perfect, but works for now. I am still interested in better ideas!!

查看更多
【Aperson】
4楼-- · 2019-02-03 04:49

This is not an answer, rather a few limitations to be aware of which don't fit in a comment.

  • All the (amazing) answers relying on ActionController::Base.perform_caching will not work for low-level caching (cf this answer). The only option you have is the module independent config.cache_store setting that you set to :null_store.

  • As @viktor-trón said earlier setting the cache_store is not possible between tests, only at init.

  • The cache is shared between environments for the default cache_store. As a result, (i) the cache should be cleared before testing if you fear stuff from your development session, (ii) running tests clears the cache of your other environments. However, your production environment should use something like the mem_cache_store or whatever else more suited for it, so it should be fine.

From the two first points, it seems that testing for low-level caching is not possible as a per example basis.

查看更多
时光不老,我们不散
5楼-- · 2019-02-03 04:50

My version that works:

RSpec.configure do |config|
  config.around(:each) do |example|
    caching = ActionController::Base.perform_caching
    ActionController::Base.perform_caching = example.metadata[:caching]
    example.run
    Rails.cache.clear
    ActionController::Base.perform_caching = caching
  end
end

Credit to Rossti, but

  1. Cache needs to be cleared between examples
  2. Cache store can not be set differently on examples, only at init in case anyone wondered
查看更多
疯言疯语
6楼-- · 2019-02-03 04:51

You're liable to end up with tests stomping on each other. You should wrap this up with ensure and reset it to old values appropriately. An example:

module ActionController::Testing::Caching
  def with_caching(on = true)
    caching = ActionController::Base.perform_caching
    ActionController::Base.perform_caching = on
    yield
  ensure
    ActionController::Base.perform_caching = caching
  end

  def without_caching(&block)
    with_caching(false, &block)
  end
end

I've also put this into a module so you can just include this in your test class or parent class.

查看更多
登录 后发表回答