1

I've got a test I'm trying to debug and I've noticed that the values are not being set to the user attributes properly. When I run p user.height_feet or p user.height_inches from the debug console, I get nil, when instead I expect the them to return 1 and 8 respectively in the first iteration. p invalid_height.first and p invalid_height.second return 1 and 8 properly, however.

Here is the code:

describe "when height is invalid" do
  invalid_height = [[1, 8], [8, 2], [5, 13], ['text', 'text'], ['text', 11], [5, 'text'], ['', '']]
  invalid_height.each do |invalid_height|
    before do
      user.height_feet = invalid_height.first
      user.height_inches = invalid_height.second
    end

    it "should not be valid" do
      debugger
      user.should_not be_valid
    end
  end
end

And the output at the debug terminal:

(rdb:1) p user.height_feet
nil
(rdb:1) p user.height_inches
nil
(rdb:1) p invalid_height.first
1
(rdb:1) p invalid_height.second
8

Someone in the #rubyonrails IRC channel suggested that it may be a scope issue and asked where my user is defined, saying that my before and it blocks may be referring to different users. I didn't think this should be an issue because I have other tests in the same spec file with both before and it blocks that run just fine. Thoughts?

Nick
  • 9,493
  • 8
  • 43
  • 66

1 Answers1

2

You need to think what your code is doing.

It goes through the each and creates a before and an it "should not be valid" but these are all eval-ed in the same scope.

So you create a load of before blocks

before do
  user.height_feet = 1
  user.height_inches = 8
end

before do
  user.height_feet = 8
  user.height_inches = 2
end

...

before do
  user.height_feet = ""
  user.height_inches = ""
end

And you create a load of it blocks

it "should not be valid" do
  debugger
  user.should_not be_valid
end

it "should not be valid" do
  debugger
  user.should_not be_valid
end

...

it "should not be valid" do
  debugger
  user.should_not be_valid
end

So the result of all of your tests is basically just

before do
  user.height_feet = ""
  user.height_inches = ""
end

it "should not be valid" do
  debugger
  user.should_not be_valid
end

Which I believe was not your intent.

The obvious fix is to use a context block. This will seal each pair of statements into a context.

[[1, 8], [8, 2], [5, 13], ['text', 'text'], ['text', 11], [5, 'text'], ['', '']
].each do |feet, inches|
  context "with an invalid height of #{feet} feet, #{inches} inches" do

    before do
      user.height_feet = feet
      user.height_inches = inches
    end

    it "should not be valid" do
      debugger
      user.should_not be_valid
    end
  end
end
Matthew Rudy
  • 16,724
  • 3
  • 46
  • 44
  • 1
    Thanks! Very informative. I'm not familiar with `context` blocks, as I'm new to ruby, but I'll look into it to learn more. – Nick Mar 29 '12 at 03:48