Testing ruby on rails page caching

written by admin on octobre 5th, 2006 @ 12:21

For the new version of iSearch, I used the page caching feature of Ruby on Rails a lot. I also needed to refresh those pages when some model where added, updated or deleted, so I needed to use cache sweeping too.

Now caching is great, but you need to be sure it works, and what's the best thing you can do to make sure it works? Write tests! But here we have a problem, as I could not find any information about page caching testing. So I decided to add some page caching test helpers to my application, and while I'm at it, released them as a plugin.

Here, I will explain how the plugin is working. Go to the plugin page if you want more information about how to download, install and use it.

First let's have a look at the init.rb file:

1
2
3
4
5
6
7
if RAILS_ENV == "test"
  require 'page_cache_test'

  Test::Unit::TestCase.class_eval do
    include Cosinux::PageCacheTest
  end
end

On line 1, we make sure that we are in the test environment so we don't interfere with other environments. If it is the case, we first load the page_cache_test.rb file on line 2. Then we include the module Cosinux::PageCacheTest in the Test::Unit::TestCase on line 4 to 6.

Now let's go in the page_cache_test.rb and see what happens when the Cosinux::PageCacheTest module is included.

1
2
3
4
5
6
module Cosinux::PageCacheTest
  def self.included(base)
    ActionController::Base.public_class_method :page_cache_path
    ActionController::Base.perform_caching = true
  end
end

The method self.included on line two, defined in the Module class is executed each time a module is included. So here it is executed because of the include we've just seen in the init.rb file.

In this method, on line 3, we change the visibility of the method page_cache_path of ActionController::Base so that we can use it in our assertions. The method is used to get the path of the cached file for a url.

Then, on line 4, we ensure that caching is enabled (it is normally disabled in the test environment).

So were are we now ? We included the Cosinux::PageCacheTest module in the Test::Units::TestCase class so each method defined in the module is available in the class. There are two instance methods defined in the module:

  • assert_cache,
  • and assert_expire.

Let's have a look at both of them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def assert_cache(*urls)
  silence do
    urls.each do |url|
      ActionController::Base.expire_page(url)
    end
  end

  if block_given?
    yield *urls
  else
    urls.each { |url| get url }
  end

  urls.each do |url|
    assert_block("#{url.inspect} is not " +
                         "cached after executing block") do
      File.exists? page_cache_path(url)
    end
  end
end

First, on line 3 to 5, we ensure that the urls we are checking are not in cache by expiring them on line 4. We also make sure that no message is logged by using the silence method which is defined at the end of the file.

Then, on line 8 and 9, if a block is given, we execute it, giving it the urls as arguments. Otherwise, on line 11, we execute a get request on each of the given urls.

Finaly, on line 14 to 18, we make sure that the urls are cached by checking that the corresponding files exists on the file system.

Now to the other method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def assert_expire(*urls)
  silence do
    urls.each do |url|
      ActionController::Base.cache_page("testing", url)
    end
  end

  yield *urls

  urls.each do |url|
    assert_block("#{url.inspect} is cached" +
                         " after executing block") do
      ! File.exists? page_cache_path(url)
    end
  end
end

As you can see, it looks quite the same, excepts a few things.

First it makes sure that the urls are cached by writing "testing" in the corresponding files on line 4.

Then we always execute a block, so that the user can take some actions that should make the urls expire, like triggering an action which defines a sweeper.

And finally, on line 12, we assert that the files corresponding to the urls do not exists anymore.

That's it. I hope this will explain how this small plugin work and that it will help somebody. Next time, I will write about my experiments with a plugin to create multiple page forms.

Comments

  • Tom on 05 oct 17:24

    How does this work with fragment caching?
  • Dam on 06 oct 15:12

    It does not, it's only for page caching. I'll add method for action and fragment caching when I use those.
  • Andrew on 18 oct 09:22

    How do you turn the caching back off? You set perform_caching = true, but now it's on for all tests. I have some cache tests in my own app, but I can only seem to get it to work for one test. Once my test is complete, I set perform_caching to false. When I try to set it to true in another test, it ignores it.
  • nodje on 04 avr 06:28

    I'm implementing an Auditing module. I'm extending ActionController::Caching::Sweeper in order to take advantage of the callbacks method and be able to persist changes on object, along with the user who did the modification. I'm new to Ruby, so looking around a good way to test that, It seems that you plugin wouldn't really allow me to test my auditing features, would it?

Post a comment

Options:

Size

Colors