Michael Durrant
Michael Durrant

Reputation: 96454

rspec - how can I refer to a let variable in the it description

I have specs that have:

describe "can translate" do
  let(:from){591}
  it "#{from}" do
    expect(Translator.three_digits(from)).to eq 'five hundred ninety two'
  end
end 

but 591 is hard-coded and repeated which I want to eliminate...
so how can I refer to from in the it description?

I tried having let(:from){591}

and then using it "#{@from}" but that doesn't show it

I also tried using it "#{from}" but that gives an error undefined local variable or method 'from' for #<Class:0x00000001bc4110> (NameError) as it's looking for a locally scoped variable.

I can avoid all these scope issues with constants, i.e.

describe "can translate" do
  FROM=592
  it "#{FROM}" do
    expect(Translator.three_digits(FROM)).to eq 'five hundred ninety two'
  end
end

With that when I get an eror I actually get A ruby file called translator.rb can translate 591 (or whatever number, the key this is that it prints out unlike all my attempt with the variable). ` but this seems like a poor approach. I prefer to avoid constant when possible and I want to do this test for several values in a row, so I need something I can change from case to case and a CONSTANT seems inappropriate.

I also tried before :all with both local and instance variables but with no success.

If I hard code the it and literally put 591 as the text and the test fails then the 591 prints out which is what I want. However I cannot get the same result working though any variable that I also use in the test.

Upvotes: 0

Views: 1949

Answers (4)

kuboon
kuboon

Reputation: 10181

describe "can translate" do
  subject { Translator.three_digits(from) }
  let(:from){|e| e.description.to_i}
  it "592" do
    is_expected.to eq 'five hundred ninety two'
  end
  # or
  specify("593"){ is_expected.to eq 'five hundred ninety three' }
end 

Upvotes: 0

zetetic
zetetic

Reputation: 47548

You can add Ruby code within the describe block to define a collection which then can be enumerated to produce multiple examples, e.g.:

describe "can translate" do
  translations = [
    {input: 591, output: "five hundred ninety one"},
    {input: 592, output: "five hundred ninety two"}
  ]
  translations.each do |t|
    context "when input is #{t[:input]}" do
      it "translates to #{t[:output]}" do
        expect(Translator.three_digits(t[:input])).to eq t[:output]
      end
    end
  end
end

Upvotes: 1

Michael Durrant
Michael Durrant

Reputation: 96454

I'm trying (and succeeding with) local variables like this:

...
describe "can translate" do
  from=738
  it from do
    expect(Translator.three_digits from).to eq 'seven hundred thirty eight'
  end 
end 
describe "can translate" do
  from=592
  it from do
    expect(Translator.three_digits(from)).to eq 'five hundred ninety two'
  end
end
...

Upvotes: 0

BroiSatse
BroiSatse

Reputation: 44675

If you want to run same test for several values, you can do:

values = [100,200,300]

values.each do |value|
  it "#{value} do
    ... # use value here
  end
end

The reason why you couldn't do this the way you tried was that it is a class method, and lets defines an instance method. Also note, that if you use let multiple times you will override previous method definition with new one. Since rspec first reads all the tests definitions and then executes them, they all will be run with the same method defined with let. Hence this will not work as expected:

values = [100,200,300]

values.each do |value|
  let(:from) { value }
  it "#{value} do
    puts from
  end

end

The above will input 300 three times.

Upvotes: 1

Related Questions