Adam Thompson Adam Thompson - 4 months ago 10
Ruby Question

Why use setup method for test suites in Ruby on Rails?

I am working through

railstutorial.org
and in our first test suite we setup an instance variable in a
setup
method.

require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

def setup
@base_title = "Ruby on Rails Tutorial Sample App"
end

test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Home | #{@base_title}"
end

test "should get help" do
get static_pages_help_url
assert_response :success
assert_select "title", "Help | #{@base_title}"
end

test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title", "About | #{@base_title}"
end
end


Why do we do this instead of just defining it straight up as an instance variable?

Answer

You are defining it as an instance variable. When the test is run the class (StaticPagesControllerTest) is instantiated and the setup function called on that instance, not on the class. If you tried to do the following instead it would define a class level instance variable not accessible from instances:

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  @base_title = "Ruby on Rails Tutorial Sample App"

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | #{@base_title}" # XXX not defined on instance
  end
...

See this page for one explanation of the difference.

You could use a class variable (@@base_title) but that might cause surprising consequences later, e.g. if you wanted to subclass the test.

Here's a quick demonstration:

class First
  @a = 'hoge'
  @@b = 'hoge'

  def initialize
    @c = 'hoge'
  end

  def give_me_a
    @a
  end

  def give_me_b
    @@b
  end

  def give_me_c
    @c
  end
end

f = First.new
# => #<First:0x007fb81607fcd0>
f.give_me_a
# => nil
f.give_me_b
# => "hoge"
f.give_me_c
# => "hoge"