For fun, I thought I would start a new Ruby on Rails project and use MiniTest instead of Test::Unit. Why? Well MiniTest is Ruby 1.9s testing framework dejour, and I suspect we will see more and more new projects adopt it. It has a built in mocking framework and RSpec like contextual syntax. You can probably get away with fewer gems in your Gemfile because of that.

Getting started is always the hardest part - let's jump in with a new rails project

rails new tddforme --skip-test-unit

Standard stuff. MiniTest sits nicely next to Test::Unit, so you can leave it in if you prefer. I've left it out just to keep things neat and tidy for now.

Now we update the old Gemfile:

group :development, :test do gem "minitest" end

and of course, bundle it all up.....from the command line:

$ bundle

Note that if you start experiencing strange errors when we get in to the generators later on, make sure you read about rails not finding a JavaScript runtime. Fire up your rails server and check everything is hunky dory if you fancy.

A Model

For the purposes of testing our test framework, we are going to put together a small model. Let's call it DevelopmentMethodology and give it a couple of fields - perhaps a name and a description.

$ rails g model DevelopmentMethodology name:string description:string

Set up the test structure

Now we have a model and a migration. I like to write my first tests now. Yes I know, crazy, before I've even migrated......anyway, because I created my project with no test-unit, I don't even have a test directory, so I'll create it now along with a few other subdirectories that will mimic the usual testing structure

$ mkdir test $ mkdir test/fixtures $ mkdir test/unit

Now, inside the test directory, I'll set up a basic test_helper file:

$ touch test/test_helper.rb

The code for my test_helper is almost boilerplate - I'm putting the Rails Environment into "test" and loading up the Rails and then simply including the minitest framework.

ENV["RAILS_ENV"] = "test" require File.expand_path('../../config/environment', __FILE__) require "minitest/autorun"

If you kept test-unit in your project, you'll have a test_helper already that will look similar to this, but won't yet bring in minitest. In this case you can choose to replace the "require" statement in that test_helper.rb file or you can create a new minitest_helper.rb file with the code.

Petit pause

Let's take a breath - go get a cup of coffee. We've covered a lot of ground. So far, the basic steps we have gone through are:

Create a new Rails project, skipping the test-unit framework

Update our Gemfile to include the minitest

Bundle

Create test directory structure

Create test_helper.rb

Writing a test

At last, we can write our first test! Create a new file in the test/unit directory - call it whatever you want, I've chosen to name mine "development_methodology_test.rb" and a basic outline goes like this:

require 'test_helper' class TestDevelopmentMethodology < MiniTest::Unit::TestCase def test_our_test_framework_can_fail assert false end end

First, we include our test_helper.rb. Then we define a class to test our DevelopmentMethodology model - it inherits from on of the classes in MiniTest. Easy peasy. Then, we create a method called test_our_test_framework_can_fail in which we simply assert false. Why would I bother to do this? Well, this little piece of code allows me to verify that I've set up MiniTest correctly - I haven't yet bothered to write any tests against my own application yet. However, when I run the test, I get valuable output (assuming everything has been set up correctly) and I can see that MiniTest is running and is producing a failing test:

[]$ ruby -Itest test/unit=development_methodology_test.rb # Running tests: F Finished tests in 0.000601s, 1665.0543 tests/s, 1665.0543 assertions/s. 1) Failure: test_our_test_framework_can_fail(TestDevelopmentMethodology) [test/unit/development_methodology_test.rb:5]: Failed assertion, no message given. 1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

I'll swiftly rewrite my test now that I know everything is working. I'm going to put a condition that a Development Methodology must contain a name.

require 'test_helper' class TestDevelopmentMethodology < MiniTest::Unit::TestCase def test_development_methodology_has_name development_methodology = DevelopmentMethodology.new assert !development_methodology.save end end

And run it

[]$ ruby -Itest test/unit=development_methodology_test.rb # Running tests: E Finished tests in 0.032036s, 31.2147 tests/s, 0.0000 assertions/s. 1) Error: test_development_methodology_has_name(TestDevelopmentMethodology): ActiveRecord::StatementInvalid: Could not find table 'development_methodologies'

It errors! But of course it does - we haven't run a migration yet. Let's do that and at the same time prepare our test database

$ rake db:migrate $ rake db:test:load

Run our test again and you should get a failing test

[]$ ruby -Itest test/unit=development_methodology_test.rb # Running tests: E Finished tests in 0.032036s, 31.2147 tests/s, 0.0000 assertions/s. 1) Failure: test_development_methodology_has_name(TestDevelopmentMethodology) [test/unit/development_methodology_test.rb:5]: Failed assertion, no message given. 1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Refactor our test

The first thing I'm going to do is refactor my test - because MiniTest includes both assert and refute statements, I think my test could be more readable if I write it like this (of course, running the test again produces a failed test as above):

require 'test_helper' class TestDevelopmentMethodology < MiniTest::Unit::TestCase def test_development_methodology_has_name development_methodology = DevelopmentMethodology.new refute development_methodology.save end end

Make the test pass

Making this test pass is simple - we just have to validate the presence of name. Edit app/models/development_methodology.rb and add in our validates

class DevelopmentMethodology < ActiveRecord::Base attr_accessible :description, :name validates_presence_of :name end

and now our test passes

$ ruby -Itest test/unit=development_methodology_test.rb Run options: --seed 20660 # Running tests: . Finished tests in 0.139823s, 7.1519 tests/s, 7.1519 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Make it purty

Now MiniTest comes with a lot built in - want your output to be in lovely colours - no problem - just run your tests like this and witness the beautiful and fabulous tests:

$ ruby -rminitest/pride -Itest test/unit=development_methodology_test.rb

Spec

A big plus point for MiniTest is the inclusion of spec by default. Watch what happens when we change our test to look like this:

require 'test_helper' describe DevelopmentMethodology do it "must have a name" do development_methodology = DevelopmentMethodology.new development_methodology.save.must_equal false end end

If you re-run your tests now, you get passing tests (obviously, because we've simply rewritten a passing test), but you've used some nice contextual RSpec like syntax all rolled up in MiniTest

That's good for today

I think that's enough of an introduction to using MiniTest with Rails. Hopefully, you've got some code to get you going so you can jump right in an explore MiniTest.