Debug failing test with assert_dom_equal

Posted by Tim Connor Wed, 25 Oct 2006 23:11:00 GMT

If you are using assert_select, which you should be, you might get into situations where you are unsure why it is failing, and its output isn’t always illuminating for that. You can do a quick sanity check by doing a


assert_dom_equal(‘foo’, @response.body)

right before the failing tests and you’ll get the full response body for the test dumped to your console.

It’s useful for discovering things like the fact that you forgot the = in <%= yield %> in your test layout.

"Extending" classes: redefining an instance method from a module via alias_method

Posted by Tim Connor Tue, 24 Oct 2006 07:50:00 GMT

The Typo plugin is finished, but it’s gotten late and I should review it before deploying and releasing it into the wild. A quick post on more I learned, though….

I had to do a fair bit of research to get the second part of the plugin working – the part where I overload/redefine a controller method from my plugin, specifically the permalink method of an ArticlesController. You can spend a lot of time reading about the intricacies of how mixins work in ruby, without getting working code. Dig through ruby-talk and you’ll learn about the difference between include/extend, what happens to “self” in different cases, the reasons for the odd module nesting and, ultimately why the ClassMethods convention caught on.

It’s not so straight-forward to overload a method, apparently, in ruby. God knows I tried each different nesting include/extend combo 6 times, with no luck. Then I came across an easier way for my case, alias_method. While that usage wasn’t exactly what I wanted, the only problem was that it did too much. I just had to drop off the unneccessary bits, and walla:

module TypoPermalinkWithId
  ....

  module ModifyArticlesController
    def self.included(base)
      base.class_eval do
        alias_method :permalink, :modified_permalink
      end
    end
    def modified_permalink
      article = this_blog.published_articles.find_by_permalink(*params.values_at(:year, :month, :day, :title))
      redirect_to article.permalink_url and return if article.nil? and article = Article.find_by_id(params[:title].to_i)
      redirect_to article.permalink_url and return if article.nil? and article = Article.find_by_title(params[:title])
      display_article(article)
    end
  end
end

ArticlesController.send :include, TypoPermalinkWithId::ModifyArticlesController

Testing plugins : Remember to require 'action_controller/test_process'

Posted by Tim Connor Tue, 24 Oct 2006 07:32:00 GMT

Before I could even get started on actually coding the second piece of the Typo plugin, I spent a lot of time wondering why I was getting the following error when trying to run my tests:

NameError: uninitialized constant ActionController::TestRequest

I kept looking at the the other plugin I’ve been working on which the tests run just fine on and scratching my head. It turns out in the working plugin I had stashed the “require ‘action_controller/test_process’” line in the testing controller I made, so I didn’t notice the difference. I’ll be moving that back for clarity tomorrow, but remember kids, if you are doing controller driven tests outside of Rails (like in a plugin) put in that line.

ActiveRecord Observers are a very handy thing for plugins

Posted by Tim Connor Sun, 22 Oct 2006 21:58:00 GMT

While developing the first piece of the typo-permalink-with-id plugin I spent a lot of time trying to get the module extend/include and module_eval stuff just right so that my code had everything it needed to not through an error when trying to add a after_create to the app code itself. After a bunch if google around I found exactly what I need in teh v2 Agile book. It wasn’t something plug-in specific, but it is a godsend to plugin writers: ActiveRecord:Observer.

Instead of trying to get your after/before code properly mixed into the app code, you can have it nice and cleanly attached via an Observer. All of a sudden my code became very simple.


module TypoPermalinkWithId
class ArticleObserver < ActiveRecord::Observer
observe Article
def after_create(article)
article.permalink = “#{article.id}-#{article.permalink}”
article.save
end
end
ArticleObserver.instance
end

Testing plugins : loading fixtures and environment

Posted by Tim Connor Sun, 22 Oct 2006 21:44:00 GMT

One of the first things I learned working on the typo-permalink-with-id plugin was how to load fixtures from a plugin. I had previously just been mocking out ActiveRecord, but the Typo object model is complicated enough that it was easier to just schlup their envirnment.rb and then load their fixtures into my tests.


require ‘test/unit’
require ‘active_record’
require ‘active_record/fixtures’
RAILS_ENV = “test”
require File.expand_path(File.join(File.dirname(FILE), ‘../../../../config/environment.rb’))

class TypoPermalinkWithIdTest < Test::Unit::TestCase

def setup fixtures_dir = File.expand_path(File.join(File.dirname(FILE), ‘../../../../test/fixtures’)) Fixtures.create_fixtures(fixtures_dir, File.basename(“blogs.yml”, ‘.*’)) Fixtures.create_fixtures(fixtures_dir, File.basename(“users.yml”, ‘.*’)) end def test_fixtures_loaded assert_not_nil Blog.find_by_id(1), “blogs.yml not loaded” assert_not_nil User.find_by_id(1), “users.yml not loaded” end

Edit: This idea slightly cribbed from Loading Fixtures in a Migration

Mocked out ActiveRecord for testing plugin

Posted by Tim Connor Fri, 20 Oct 2006 06:06:00 GMT

I mentioned this in my previous post, but to make my plugin easier to test I tried to make it not need to touch the DB, which was interesting to do, given that scaffold_resource is very much tied to a model. This was a big inspiration and this the final (as of now) result:


class Resource < ActiveRecord::Base
@count = 1 def self.count() @count end
def self.columns() columns ||= []; end def self.column(name, sql_type = nil, default = nil, null = true) columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) end def self.find(param) return param == :all ? [Resource.new{ |m| m.id = 1; m.name = 'bob' }] : Resource.new{ |m| m.id = 1; m.name = 'bob' } end def save() @count += 1 and return true if valid? end
def destroy() @@count -= 1 end
column :name, :string
end

Manually setting id in Rails 2

Posted by Tim Connor Fri, 20 Oct 2006 00:12:00 GMT

In testing DynamicScaffoldResource, I have been working on sort of mocking/overloading ActiveRecord so that it doesn’t touch the DB, so I can minimize how much it depends on the root Rails environment to test, since it’s a plug-in.

class Resource < ActiveRecord::Base
  def self.columns() @columns ||= []; end
  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
  end
  def self.find(param)
    return param == :all ? [Resource.new(:id => 1, :name => 'bob')] : Resource.new(:id: => 1, :name => 'bob')
  end

  column :id,            :integer
  column :name,          :string

  validates_presence_of :name
end

Well Rails treats the id as a special field, since it is. I tried letting it implicitely add it, and explicitely as above, but there was no way I seemed to be able to set it manually and access it (maybe the problem is prior to a save?), so my edit named route in the view wouldn’t choke (the show path had no problem with the nil, which I might not have caught for a while). While there is probably some way to open up access to the id column, this mailing list post opened up an alternative that works, just use:


Resource.new{ |m| m.id = 1; m.name = ‘bob’ }