Friday, 21 September 2012

Getting started with Ruby on Rails 3.2 and MiniTest - a Tutorial

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.

Friday, 14 September 2012

Javascript - Objects by ref

If any language should have been name after a snake, Javascript should have. It's a slippery little thing I tell you. It slithers and slides and wraps around you. And you have to work like a snake charmer to coax it out of its basket and make it play nicely without biting you.

Take, for example the simple idea of passing a variable by ref or by val. Javascript's snakey little implementation means that if you are passing a variable then you'll never pass it by ref. However if you are passing an object, then, hey presto, by ref it is. Bear witness:

var globalVar;
      var anObj = function() {
        this.value = "default value";
      }

      function changeValue(arg){
        arg.value = "Changed by function";
      }

      function changeUp(arg) {
        arg = "Changed";
      }


      globalVar = "global";
      console.log(globalVar);
      changeUp(globalVar);
      console.log(globalVar);

      var myObj = new anObj();
      console.log(myObj.value);
      changeValue(myObj);
      console.log(myObj.value);

Yep, slap that into some html and run it with your Chrome developer console up and about and you will see something like this:

global
global
default value
Changed by function

Yes sir! that Javascript. She's a tricky little snake of a language. Nothing at all like Python. Nothing at all like Asp. Nope, it's in a league of its own.

Tuesday, 4 September 2012

Ruby frameworks, Rails and Padrino

Some thoughts on the Padrino and Rails. For the past few weeks, I've been working on a small project that is using Padrino rather than Rails. The interesting thing was that the decision for the technology was based on the idea that the project was only going to have a few objects; at most five or six and as such, didn't need something as large, complex or weighty as Rails. However, something as barebones as Sinatra would not allow for some of the more rapid application development that you get from some of the baked in goodness of Rails - things like Sessions, Flash, Form helpers and generators all speed up development fairly considerably. With that in mind, Padrino was the framework of choice.

Now Padrino is interesting. It's a great little framework, but, the temptation is to look at it's relative light-weightedness in comparison to Rails and think it will require less learning time or up-front knowledge for someone with little experience of the framework or of something like Rails. This is really a false economy. I would, in fact, say that for a beginner, Rails, not Padrino, is the sensible choice. Rails has excellent documentation right out of the gate, Padrino - well the documentation is just okay. It's enough for a seasoned developer to use, but unless you are already familiar with Rails, you might find yourself floundering a bit trying to figure out how to do something relatively simple.

The other area in which Rails really excells is in the sensible defaults - Padrino, in a way, requires you to really know your technology up front. Padrino is less opinionated than Rails and allows you to plug in various different components to pretty much any part of the system, even coding your own if you fancy. However, this kind of flexibility comes at a price - you need to know what you're going to use up front - Datamapper? ActiveRecord? Sequel? With Rails, the decision has been made for you - ActiveRecord. No faffing about with analysis paralysis. On the other hand, this kind of agnostic framework is good for those with specific requirements to use the non-defaults.

Where Padrino really shines in my opinion, is in the admin support. Generating an admin backend to your app is so simple. Granted with Rails you can use ActiveAdmin or something, but really, having this kind of CRUD baked in to a framework is awesome - one of the things, incidentally, that I love about Django.

So, when should you use Padrino? Well, my advice is, when you already know Rails and you want a framework that's a little bit smaller. But, heed this will if you are new to Ruby based web frameworks - learn Rails first.