Writing Rails helper tests/specs using MiniTest::Spec

So MiniTest has been receiving a lot of attention recently as being the testing framework for Ruby. Supporting TestUnit and Rspec syntax it appeals to both camps while also offering a much lighter, faster codebase.

This week I bundled together a gem with a bunch of helper methods and CSS classes that I always seem to re-write across every app that I work in. Since the gem is still pretty basic and subject to change a lot before I settle on a stable version 1 I figured this would be a good project to experiment with MiniTest::Spec.

Moving to MiniTest::Spec

I prefer the Rspec flavour so named and structured my test files like so:

spec/
  - spec_helper.rb
  - dummy # a dummy rails app for testing
  - helpers
  - support # extra files for spec support, more on these in a minute 

Note - Using this structure, you'll also have to update your Rakefile a little:

# Rakefile
Rake::TestTask.new(:spec) do |t|
  t.libs << 'lib'
  t.libs << 'spec'
  t.pattern = 'spec/**/*_spec.rb'
  t.verbose = true
end

... and modify spec_helper.rb to look like this:

# Configure Rails Environment
ENV["RAILS_ENV"] = "test"

require File.expand_path("../dummy/config/environment.rb",  __FILE__)

require "rails/test_help"

require "minitest/rails"

Rails.backtrace_cleaner.remove_silencers!

# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

Creating a dummy class for the specs

Since Rails helpers are modules, we need to define a class to include the module in so we can test the methods. Your helper methods may also call Rails view helper methods so our class should behave just like a normal Rails view.

# spec/support/dummy_class.rb

# define a class that inherits from ActionView::Base
class DummyClass < ActionView::Base
  # include each of your Rails helpers here
  include MyHelper
end

Usually we access the helper through a method provided by rspec-rails named helper. We can recreate that same behaviour by defining this method:

# spec/spec_helper_methods.rb

def helper
  @helper ||= DummyClass.new
end

This method should now be available to all of our specs. We can call it like so:

require "spec_helper"

describe UsersHelper do

  describe :my_method do
    helper.my_method("arg").must_equal "<div class='someclass'>arg</div>"
  end

end

You can run your specs by running rake spec

Testing rails helper methods using MiniTest::Spec

The next problem I ran into was that, using MiniTest's must_equal I had to specify exactly what the output from the view helpers would be.

I find this is very brittle. For example, consider this method:

def bodacious_div(content, klass, id)
  %{<div class="#{klass}" id="#{id}">#{content}</div>}.html_safe
end

And this test:

  describe :bodacious_div do
    it "should return a div with class, id and content" do
      helper.bodacious_div("hello", "my_class", "my_id").must_equal %{<div id="my_id" class="my_class">#{content}</div>}
    end
  end

This test would fail because the ID and class attributes are in the wrong order. In other words, the method is behaving as I'd like it to but the test fails because the syntax isn't exact.

This is too brittle for my liking, I'd rather access a matcher like ActionController's assert_dom_equal.

To add a custom matcher, all we have to do is extend the MiniTest::Matchers module:

# spec/support/mini_test/assertions.rb
module MiniTest::Assertions

  def assert_dom_equal(expected, actual, message = nil)
    expected_dom = HTML::Document.new(expected).root
    actual_dom   = HTML::Document.new(actual).root
    message      = "expected:\n #{actual}\nto equal:\n#{expected}"
    assert_block(message) { expected_dom == actual_dom }
  end

end

This assertion isn't useful in Spec style MiniTests yet though, it's written in the UnitTest assertion syntax. To add it to the MiniTest::Spec expectations, we just need to call the method infect_an_assertion within MiniTest::Expectations

# spec/support/mini_test/expectations.rb

module MiniTest::Expectations

  infect_an_assertion :assert_dom_equal, :must_be_dom_equal, :reverse

end

The first argument refers to the assertion method we should call, the second argument is the name of the expectation we're defining. The reverse argument states whether or not we want to define an opposing expectation (wont_be_dom_equal)

So far, Miniest seems really cool. I'll posting more on this topic as I discover more in the near future.

If you'd like to check out the box_of_tricks gem, you can find it on github: github.com/KatanaCode/box_of_tricks

0 comments

Manage your application version using per-version

At the moment my team are working on a client application that's gaining more and more public support.

Part of the contract between them and their business clients is regular software updates that are well documented and broadcast amongst the network of paying clients.

To make maintaining the application version easier I bundled together a simple Ruby gem that provides everything required to document versions.

Installation

Installing is straight-forward: add per-version to your Gemfile and then run bundle install.

# Gemfile

gem "per-version"

Once installed, you'll have to run this generator script:

$ rails g version_file

That will stick a file named VERSION in the root directory of your application which looks like this:

VERSION = "0.0.1"

Show current version

So anytime you're working away and you want to know the current working version of your application run rake version:show

$ Current Version: 2.0.1

Release a new version

Once you've added a bunch of awesome features and want to launch a new version.

  1. Make sure your git commits are up to date.
  2. Change VERSION to show the next version number.
  3. git commit -am "Updated version for new release"
  4. rake version:release

Simples!

The gem is still in it's infancy so I'd appreciate all/any feedback

To bring yourself up-to-date on semantic versioning check out Semver: Semantic Versioning

0 comments

DRYing Up Your Code With A Little Metaprogramming

An introduction to Metaprogramming

Metaprogramming in a nutshell is writing code that writes code. Here’s a really simple example:

<% 100.times do |number| %>
  <%= content_tag :strong, "hello" %><br />
<% end %>

Will output <strong>hello</strong> a hundred times.

This really simple example illustrates the power of metaprogramming; in theory, infinite lines of code can be written by just a few lines of your code.

The Rails source code is full of examples of metaprogramming, ever wondered how Active Record is able to provide methods like find_by_username()?

Here are a couple of examples of how you can clean up your code using metaprogramming techniques.

Some metaprogramming tips

Suppose you have an model, say Comment, that can exist in several states: unflagged, flagged, approved and removed. The comments table has an integer column called state that represents each of these states:

class Comment < ActiveRecord::Base
  # comment state is 1 by default and then changes as it is flagged, approved etc.
  STATES = { 
    :unflagged => 1,
    :flagged   => 2,
    :approved  => 3,
    :removed   => 4
  }
end

You want methods to check if the Comment is or isn’t in one of these states so you add the following:

class Comment < ActiveRecord::Base

  # comment state is 1 by default and then changes as it is flagged, approved etc.
  STATES = { 
    :unflagged => 1,
    :flagged   => 2,
    :approved  => 3,
    :removed   => 4
  }

  def unflagged?
    state == 1
  end

  def flagged?
    state == 2
  end

  def approved?
    state == 3
  end

  def removed?
    state == 4
  end
end

Great! Now you can call @comment.flagged? or @comment.approved? etc.

This is not ideal though, those four methods are really similar!

Defining methods on the fly.

By using “define_method” we can achieve the exact same thing as we have above but with much less fuss! Check this out:

class Comment < ActiveRecord::Base

  STATES = { 
    :unflagged => 1,
    :flagged   => 2,
    :approved  => 3,
    :removed   => 4
  }

  STATES.each_pair do |key, value|
    define_method "#{key}?" do
      state == value
    end

  end
end

For each key in the hash (the names of our states) a new method is created that checks if the object’s state is equal to value. Twelve lines of code condensed into 4 – Magic!

Lets also add methods to change the state of each comment:

class Comment < ActiveRecord::Base

  STATES = { 
    :unflagged => 1,
    :flagged   => 2,
    :approved  => 3,
    :removed   => 4
  }.each_pair do |key, value|
    define_method "#{key}?" do
      state == value
    end

    define_method "to_#{key}" do
      update_attribute :state, value
    end

  end
end

When we create a new hash, the hash itself is returned so we can call each_pair directly on the hash making this code even neater. We now also have methods that will change the state: to_unflagged, to_flagged, to_approved, to_removed.

If you have models in your applications that exist in one of several states then this technique could really come in handy to clean up your code. You may also be interested in the enum-colum plugin. Enum columns are like string columns but can only have limited amount of permitted values. This is a lot easier to keep track of than using integers like I have in this example.

Update

For more metaprogramming, check out this article on metaprogamming

1 comment

DRYer, neater Rails before_filters using classes

Recently I was working on a project which required various permissions for each controller. A user could have permission to access one feature of the site but not another.

Here’s a great tip for keeping your rails controllers simple and DRY when working with multiple before filter conditions.

The before_filter method takes not only a method name as an argument, it can also take custom class objects as an argument. Here’s an example:

class OrdersController

  # run this before filter on :index, :show and :destroy actions
  before_filter PermissionCheck.new( :orders, :only => [:index, :show, :destroy] )

end

When requests are made to those actions that require this before filter, Rails will create a new instance of PermissionCheck and call it’s before() method (you have to define this method yourself). Here’s an example of the PermissionCheck class and how it works:

# lib/permission_check.rb
# Here we create a new subclass of Struct, an easy way to create a class with an attribute.
class PermissionCheck < Struct.new( :permission_name )

  # NOTE  - here it is assumed that you have
  # a) A method to find the current_user from the controller: ApplicationController#current_user
  # b) A method to check if the current_user has a specific permission: User#has_permission?
  # c) A method to redirect and notify the user if they do not have adequate permissions: ApplicationController#unauthorized_action

  # this is called from the controller automatically when we use before_filter
  def before( controller )
    # unless the current_user has permission...
    unless controller.current_user.has_permission?( permission_name )
    # redirect and notify user
      controller.unauthorized_action
    end
  end


  # after_filters can be defined in the same way
  def after( controller )

  end

end

To make things neater still, we can create a class method for this in ApplicationController:

class ApplicationController < ActionController::Base

  # Helper method to add this before filter to the controller
  def self.check_permission( permission, options = {} )
    before_filter PermissionCheck.new( permission ), options
  end

end

And our controllers now look like:

class OrdersController < ApplicationController

  check_permission :orders, :only => [:index, :show, :destroy]

  # etc...

end

class CustomersController < ApplicationController

  check_permission :customers, :only => [:index, :destroy]


  # etc...
end

Defining classes for before_filters and after_filters offers far more flexibility than simply using methods so, if your before_filters are starting to mount up and they contain a lot of similar code then defining a class may be a better solution for you.

0 comments

Calling One Rake Task from Another

A quick ruby tip for calling one rake task from another rake task:

namespace :mytasks do

  desc "Task number one"
  task :one do
    # do something here
  end

  desc "Task number two"
  task :two do
    Rake::Task["mytasks:one"].execute
  end

end

Note: Even although task one and task two are within the same namespace, you still have to include the full name (namespace and task name) in the method call.

0 comments