Testing Ramaze

Ramaze uses and encourages BDD (Behaviour Driven Development). Ramaze itself is tested using Bacon and supports it out of the box, it however isn't limited to just Bacon.

One might wonder why to bother with writing tests. The answer to this is quite simple: stability. Manually testing an application works on a very basic level but there are various issues that will arise once your application grows. The two biggest issues are human errors and repeatability. Especially the latter becomes an issue when your development team grows in size, while the initial developer may be willing to manually test every feature every time a change has been made others might not. Even worse, there's a chance they won't test their code at all and assume it's production ready because on their setup.

Writing tests that can be executed using a single command (or automatically) makes your life a lot easier as you no longer have to worry about any of these issues (assuming people actually write tests). Whenever somebody commits code they write a test and you can easily verify if it works on different setups by simply running said test.

When writing Ruby code you can pick from a large collection of testing libraries such as Bacon and Rspec for general tests, SimpleCov for code coverage and Capybara for testing form based actions and the like. Of course the list doesn't stop here, there's simply too much to discuss everything.

Bacon

Bacon is a small and lightweight Rspec clone that's used by Ramaze and Innate and is the recommended tool to use. Each bacon test consists out of at least two bits: a "describe" block and an "it" (or "should") block. The describe block can be seen as a group of multiple it/should blocks. In most cases these blocks are used to specify the name of a class, module, etc. The it/should blocks are used for individual tests.

Lets take a look at a simple block of code:

class Person
  attr_accessor :name

  def initialize(name = nil)
    @name = name
  end
end

Using Bacon we can test this code as following:

require 'bacon'

describe 'Person' do
  should 'respond to #name' do
    person = Person.new

    person.respond_to?(:name).should  == true
    person.respond_to?(:name=).should == true
  end

  should 'set the name in the constructor' do
    person = Person.new('Matz')

    person.name.should == 'Matz'
  end

  should 'set the name using #name=' do
    person = Person.new

    person.name = 'Matz'

    person.name.should == 'Matz'
  end
end

For more information on the syntax of Bacon and other information see the Bacon Github project.

Bacon With Ramaze

Ramaze makes it easy to test your code using Bacon by providing you with a small helper file. This file can be loaded as following:

require 'ramaze/spec/bacon'

This file adds two bacon contexts (rack_test and webrat), configures Ramaze to only show error messages and adds a few helper methods.

Bacon and Rack::Test

In order to test Ramaze specific code you'll need to use a tool that's capable of mocking Rack requests or execute this request in a different way (e.g. using Selenium). Rack::Test (gem install rack-test) makes it possible to test your Rack based (and thus Ramaze) applications without having to use a webbrowser.

Ramaze makes it easy to use Rack::Test by defining a special bacon context: "rack_test". This context can be used by calling behaves_like :rack_test inside your describe block:

describe 'Using Rack::Test' do
  behaves_like :rack_test
end

Once loaded you can execute HTTP requests using methods such as get:

describe 'Using Rack::Test' do
  behaves_like :rack_test

  should 'display the homepage' do
    get('/').body.should == 'Hello, Rack::Test!'
  end
end

More information about Rack::Test can be found on the Github page of Rack::Test.

Capybara

Capybara is a Gem that can be used to simulate browser requests using Rack::Test, Selenium or other drivers, it's even capable of testing Javascript based code using Selenium.

In order to use Capybara you must first install it:

$ gem install capybara

Once installed you'll have to configure Capybara so it knows how to use your Ramaze application. Depending on the testing Gem you're using you'll also have to configure said Gem, for this guide it's assumed that you're using Bacon.

First you should load and configure Capybara:

require 'capybara'
require 'capybara/dsl'
require 'bacon'

# Tells Capybara which driver to use and where to find your application.
# Without this Capybara will not work properly.
Capybara.configure do |config|
  config.default_driver = :rack_test
  config.app            = Ramaze.middleware
end

Next you'll have to set up a context for Bacon:

shared :capybara do
  Ramaze.setup_dependencies
  extend Capybara::DSL
end

Last but not least, make sure Ramaze knows about your root directories and set your mode:

Ramaze.options.roots << 'path/to/spec/directory'
Ramaze.options.mode  = :spec

Once all of this has been done you can start using Capybara. A simple example of this is the following:

class MainController < Ramaze::Controller
  map '/'

  def index
    return 'Hello, Ramaze!'
  end

  def redirect_request
    redirect(MainController.r(:index))
  end
end

describe 'Testing Ramaze' do
  behaves_like :capybara

  it 'Go to the homepage' do
    visit '/'

    page.has_content?('Hello, Ramaze!').should == true
  end

  it 'Follow redirects' do
    visit '/redirect_request'

    page.current_path.should == '/index'
    page.has_content?('Hello, Ramaze!').should == true
  end
end

For more information on how to use Capybara with other testing tools, how to use the syntax and so on you should resort to the Capybara Github page.

Code Coverage using SimpleCov

To test the Ramaze application tests coverage, you can use a tool like SimpleCov. SimpleCov requires minimal effort to get integrated, start by installing the gem:

gem install simplecov

In order to actually measure your code coverage you'll have to tell SimpleCov a bit about your application. This is done by loading Simplecov and starting it before loading all your tests. This can be done by using the following code:

require 'simplecov'

SimpleCov.start

# Load the existing files
Dir.glob('spec/*.rb').each do |spec_file|
  unless File.basename(spec_file) == 'init.rb'
    require File.expand_path(spec_file)
  end
end

In order to run the file you'd simply invoke the following:

bacon spec/init.rb

Upon success SimpleCov will create a new directory coverage with the results. You can point your browser to the index.html file inside that directory to view the results.

For more information on using Simplecov see the Github project.