Reputation: 96454
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
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
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
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
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