Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-10 of 19 total  RSS 

load all fixtures

In some test cases I need all my fixtures to be loaded. To make this easier, add the following to test/test_helper.rb:

class Test::Unit::TestCase
  def self.all_fixtures
    Dir[File.dirname(__FILE__) + "/fixtures/*.yml"].each do |f|
      fixtures File.basename(f, '.yml')
    end
  end

  ..
end


and in your tests use it as follows:

class FooTest < Test::Unit::TestCase
  all_fixtures

  ..
end


Happy testing!

Make Time "Stand Still" in Ruby

When writing tests, it's sometimes difficult to test results of methods that use current time. Two calls to Time.now can give different results and cause test failures. Here is some code that lets you execute a block during which Time.now will return a consistent value:

class Time

  # this code adds a Time.freeze method to make time "stand still"
  # during execution of a block. This can be helpful during testing of
  # methods that depend on Time.new or Time.now
  #
  # Example:
  #
  #   Time.freeze do
  #      puts Time.new.to_f
  #      # ... do stuff; real time passes
  #      puts Time.new.to_f     # outputs same time as above
  #   end
  #   # ... time returns to normal
  #
  # An optional Time object may be passed to freeze to a specific time:
  #
  #   Time.freeze(Time.at(2007, 11, 15)) do
  #      # ...
  #   end
  #
  # While inside the block, Time.frozen? will return true

  class << self

    def now
      @time || orig_new
    end

    alias_method :orig_freeze, :freeze
    alias_method :orig_new, :new
    alias_method :new, :now

    # makes time "stand still" during execution of a block. if no time is
    # supplied, the current time is used. While in the block, Time.new and
    # Time.now will always return the "frozen" value.
    def freeze(time = nil)
      raise "A block is required" unless block_given?
      begin
        prev = @time
        @time = time || now
        yield
      ensure
        @time = prev
      end
    end

    def frozen?
      !@time.nil?
    end

  end
end

rcov rake task for rails project

This task will create a folder (doc/coverage) then run all of your tests and produce HTML with code coverage information in that folder. If you are on a mac it will even open the index.html file up for you automatically

# this requires the RCOV gem to be installed on your system
namespace :test do
  desc "Generate code coverage with rcov"
  task :coverage do
    rm_f "doc/coverage/coverage.data"
    rm_f "doc/coverage"
    mkdir "doc/coverage"
    rcov = %(rcov --rails --aggregate doc/coverage/coverage.data --text-summary -Ilib --html -o doc/coverage test/**/*_test.rb)
    system rcov
    system "open doc/coverage/index.html" if PLATFORM['darwin']
  end
end

Helper for testing default routes generated by a resource in Ruby on Rails

These methods test that the routes for resources defined in routes.rb are working as expected. Call them from your functional (controller) tests.

Add the following 3 methods to test/test_helper.rb (updated for Rails 1.2.5 which no longer uses semicolons as a separator for the edit action):
# Test for routes generated by map.resource (singular).
def assert_routing_for_resource(controller, skip=[], nesting=[])
  routes = [
    ["new",'/new',{},:get], ["create",'',{},:post],
    ["show",'',{},:get], ["edit",'/edit',{},:get],
    ["update",'',{},:put], ["destroy",'',{},:delete]
    ]
  check_resource_routing(controller, routes, skip, nesting)
end
# Test for routes generated by map.resources (plural).
def assert_routing_for_resources(controller, skip=[], nesting=[])
  routes = [
    ["index",'',{},:get], ["new",'/new',{},:get], ["create",'',{},:post],
    ["show",'/1',{:id=>'1'},:get], ["edit",'/1/edit',{:id=>'1'},:get],
    ["update",'/1',{:id=>'1'},:put], ["destroy",'/1',{:id=>'1'},:delete]
    ]
  check_resource_routing(controller, routes, skip, nesting)
end

# Check that the expected paths will be generated by a resource, and that
# the expected params will be generated by paths defined by a resource.
# routes is array of [action, url string after controller, extra params].
def check_resource_routing(controller, routes, skip=[], nesting=[])
  # set a prefix for nested resources
  prefix = nesting.join('s/1/')
  unless prefix.blank?
    prefix += "s/1/"
  end
  # Add params for nested resources.
  # For each 'nest', include a ":nest_id=>'1'" param.
  params = {}
  nesting.each do |param|
    params["#{param}_id".to_sym] = '1'
  end
  # Test each of the standard resource routes.
  routes.each do |pair|
    unless skip.include? pair[0]
      assert_generates("/#{prefix}#{controller}#{pair[1]}",
        {:controller=>controller,
        :action=>pair[0]}.merge(pair[2]).merge(params), {}, {},
        "Failed generation of resource route for action #{pair[0]} /#{prefix}#{controller}#{pair[1]}")
      assert_recognizes(
        {:controller=>controller,
          :action=>pair[0]}.merge(pair[2]).merge(params),
        {:path=>"/#{prefix}#{controller}#{pair[1]}", :method=>pair[3]},
        {}, "Failed to recognize resource route for path #{pair[3]}:/#{prefix}#{controller}#{pair[1]}")
    end
  end
end

EXAMPLES

You can specify actions to 'skip' (if you have a special route for that action).
If using nested resources, set the nesting array (use singular strings).

So, if you have the following in routes.rb:
map.make_thing '/make', :controller=>'things', :action=>'new'
map.resources :nests do |nest|
  nest.resources :things
end
map.resource :foo

then you can use the following in things_controller_test.rb:
def test_resource_routing
  assert_routing_for_resources 'things', ['new'], ['nest']
  assert_routing_for_resource 'foo'
end

Testing for Exception message in Rails

e = assert_raise(RuntimeError) { my_code_that_raises }
assert_match(/Error message here/i, e.message)..

Custom headers in Rails tests

From time to time you may need to set headers in your functional tests that aren't supported by the @request object. I had to set up my request with Basic authentication.

Add an extension to the TestRequest class in the test/test_helper.rb file:

class ActionController::TestRequest 
  def set_header(name, value)
    @env[name] = value
  end
end


Then set values as required in your functional test.

def test_index
  @request.set_header "HTTP_AUTHORIZATION", "Basic " + Base64.encode64('testuser:testpass')
  get :index
  assert_response :success
  assert_template "index"
end

In Place Testing for Ruby methods

This is something kinda experimental I'm working on. Testing is cool, but I hate that it's separate from my code. Perhaps that's stupidity on my part, but I wanted to see if there's a way to bring the lowest level of testing directly into the class..

module InPlaceTesting
  def self.included(klass)
    old_method_added = klass.method(:method_added)
    new_method_added = lambda do |m|
      @@current_method = m
      old_method_added.call m
    end
    
    # Next line inspired by http://utils.ning.com/ruby/dbc.rb by Brian McCallister and Martin Traverso
    (class << klass; self; end).send :define_method, :method_added, new_method_added
    
    class << klass
      def given(*args)
        self.new.send @@current_method, *args
      end
      def method_should(message, params)
        unless params[:return] == params[:when]
          puts "\"#{@@current_method}\" fails to #{message} (returns #{params[:when]} instead of #{params[:return]})"
        end
      end
    end
    
  end
  
end

class DumbClass
  include InPlaceTesting

  def add(x,y) 
    x + y
  end
  method_should "add 5 and 4", :return => 9, :when => given(5, 4)

  def subtract(x,y) 
    x - y
  end 
  method_should "subtract 5 from 14", :return => 9, :when => given(14,5)
  
  def increment(x)
    x + 1
  end
  method_should "increment 12", :return => 13, :when => given(12)
end

test

// description of your code here

<?
	if (in_array($r["type"], Array(1, print str_replace("; ;","",(get_part_of_text($desc, 300)));
	else { $sql->query("SELECT of.phone FROM offers o, offices of
			WHERE o.office_id=of.id AND o.id=".$r["id"]);
		list($office_phone) = $sql->getrow(
print (str_replace("; ;","",(get_part_of_text($desc,300))))."<br/><b>Contacts</b>:".$office_phone;
	}

#post method in tests with a different controller

I wanted a #login method in test_helper that would allow me to easily login from any of my functional tests. However, the #post method won't allow you to set a different controller than the one in the @controller instance variable that's defined in your test's #setup. Well, by looking at how the #process method works, you can see that it just grabs the controller from @controller. Redefine that, and you're good to go:
old_controller = @controller
@controller = LoginController.new
post(
  :attempt_login,
  {:user => {:name => 'joe', :password => 'password'}}
)
@controller = old_controller

If you have several login methods, such as a #login_admin and #login_regular, you could make a wrapper to reduce duplication:
def wrap_with_controller( new_controller = LoginController )
  old_controller = @controller
  @controller = new_controller.new
  yield
  @controller = old_controller
end

def login_admin
  wrap_with_controller do
    post(
      :attempt_login,
      {:user => {:name => 'root', :password => 'password'}}
    )
  end
end

def login_regular
  wrap_with_controller do
    post(
      :attempt_login,
      {:user => {:name => 'joe', :password => 'password'}}
    )
  end
end

Create YAML test fixtures from database in Rails

As found at http://media.pragprog.com/titles/fr_rr/code/CreateFixturesFromLiveData/lib/tasks/extract_fixtures.rake

desc 'Create YAML test fixtures from data in an existing database.  
Defaults to development database.  Set RAILS_ENV to override.'

task :extract_fixtures => :environment do
  sql  = "SELECT * FROM %s"
  skip_tables = ["schema_info"]
  ActiveRecord::Base.establish_connection
  (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|
    i = "000"
    File.open("#{RAILS_ROOT}/test/fixtures/#{table_name}.yml", 'w') do |file|
      data = ActiveRecord::Base.connection.select_all(sql % table_name)
      file.write data.inject({}) { |hash, record|
        hash["#{table_name}_#{i.succ!}"] = record
        hash
      }.to_yaml
    end
  end
end
« Newer Snippets
Older Snippets »
Showing 1-10 of 19 total  RSS