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