Testing multiple calls to an object

Manfred Stienstra, 29 Apr 2008, 12:14 in testing (edit).

Have you ever wanted to test multiple writes to $stderr? Mocking frameworks aren’t good at that, instead you can write a simple class to record method calls.

class Receptor
  require 'singleton'
  include Singleton
  
  attr_accessor :messages
  
  def initialize
    @messages = []
  end
  
  def method_missing(*attrs)
    self.messages << attrs
  end
end

$stderr = Receptor.instance

And in your tests:

messages = Receptor.instance.messages
assert messages.include?(['puts', "[!] Error!"])
assert messages.include?(['puts', "[?] Couldn't find preferences file."])

1 comment

Quick Fix for acts_as_paranoid

Norbert Crombach, 17 Jul 2007, 08:26 in ruby on rails, testing, and broken (edit).

For those of you on Edge Rails, since changeset [7189] appears to have broken the current acts_as_paranoid we’ve been getting some test errors. There’s a quick patch I wrote available in this Pastie, but because scope_out is now recommended by Rick Olson himself this should only be seen as a migration path. Hopefully this will save you some trouble.

No comments yet

Code to Test Ratio Showdown

Manfred Stienstra, 03 May 2007, 17:40 in ruby on rails and testing (edit).

We had a little Code to Test Ratio showdown at the office today, probably because there was a woman present. It got me wondering what the Code to Test Ratio for other people is. So everybody, please post the CTTR of your current project in the comments.

Note: in Rails you can find your CTTR with rake stats.

17 comments

Testing with attachment_fu

Manfred Stienstra, 26 Apr 2007, 10:56 in ruby on rails and testing (edit).

When you’re testing uploads with attachment_fu, your files end up in RAILS_ROOT/public by default. This is not very handy because they might override your carefully uploaded bunny pictures in development. You can easily solve this by overriding the full_filename method on your attachment model. Let’s assume you have something like this.

class Asset < ActiveRecord::Base
  belongs_to :post  
  has_attachment :content_type => :image, :storage => :file_system
end

Then you can add the following to the file your tests are defined in:

class Asset
  def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
    File.join(Dir::tmpdir(), file_system_path, *partitioned_path(thumbnail_name_for(thumbnail)))
  end
end

This will make your files get written to /tmp/public. If you have multiple tests that have to override the attachment class, it’s probably best to put it in a separate file.

6 comments

Using OpenStruct as mock for ActiveRecord

Manfred Stienstra, 07 Mar 2007, 15:53 in ruby on rails and testing (edit).

As you may have noticed OpenStruct#id always returns the object id of the OpenStruct instance, even when you set id.

>> o = OpenStruct.new :id => 2
=> #<OpenStruct id=2>
>> o.id
(irb):4: warning: Object#id will be deprecated; use Object#object_id
=> 9850940

Fortunately there is a simple way around this.

OpenStruct.__send__(:define_method, :id) { @table[:id] }

Now OpenStruct behaves like we want.

>> o.id
=> 2

Note that hash and object_id still work fine. You probably want to keep in mind that we’ve redefined the default OpenStruct behaviour and it might cause problems elsewhere.

1 comment

Validating feeds in functional tests

Manfred Stienstra, 02 Feb 2006, 13:58 in ruby on rails and testing (edit).

In the past I usually tested the feeds a Rails application generated by writing a functional test that checked the HTTP status code and matched certain strings in the feed using a regular expression. If that checked out I hand-tested the feed using the online feedvalidator. Needless to say, this became very cumbersome after a few times, especially for one of our projects that generates a whole list of different feeds depending on the state of the account. Time to add validation to the functional tests.

Unfortunately the feedvalidator is (not yet) written in Ruby, so we have to do system calls to a python script to validate. I installed the feedvalidator in the script directory, which looked like the correct place to put this. A protected method on the testcase makes sure we can easily test feeds.

def validate_feed(content)
  validate = File.dirname(__FILE__) + '/../../script/feedvalidator/validate.py'
  path = Pathname.new(File.dirname(__FILE__) + '/../tmp')
  Tempfile.open('feed', path.cleanpath) do |tmpfile|
    tmpfile.write(content)
    tmpfile.flush
    result = `#{validate} #{tmpfile.path} A`
    unless result =~ /No errors or warnings/
      raise "Feed did not validate: #{result}"
    end
  end
end

So now the testcases looks like this:

def test_atom
  get :atom
  validate_feed @response.body
  assert_equal 'application/atom+xml', @response.headers['Content-Type']
end

Note that this validates the feeds on level ‘A’ which only tests for MUST directives. For completeness you should probably still test either with the online validator or temporarily set the validation to ‘AA’ or even ‘AAA’.

Rumor has it that if you validate your feeds at ‘AAA’ level Mark Pilgrim will come to your house and crown you Prins of the Feeds. Lucky lucky!

4 comments

Test your plugins!

Manfred Stienstra, 09 Dec 2005, 10:55 in ruby on rails and testing (edit).

Test are supposed to be run often, but they only get run if they’re easy to run. When you create a plugin in your Ruby on Rails project, it doens’t get run by default.

And that’s not very easy now, is it? Fortunately there is a standard task to run the plugin tests, which is called `test_plugins’. How do we get this task to run all the time?

RoR allows us to specify our own tasks in /lib/tasks, so we’re going to add a file called `test_plugins_by_default.rake’ to this directory, and we put the following in the file:

desc "Run test:plugins by default."
task :default do
  namespace 'test' do
    Rake::Task[:plugins].invoke
  end
end

Very well sir, but why does this work? The Rake User Guide tells us that a task that is declared multiple times, cumulatively adds it’s actions to the task. So ‘test_plugins’ will now be run in the default task.

No comments yet