Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rspec way for passing variable between multiple contexts

Tags:

ruby

rspec

rspec2

I was wondering what would be the best way to pass variable between multiple contexts (or multiple its) in rspec but without using global variables?

For example, I have this:

describe "My test" do
    let(:myvar) { @myvar = 0 }

    context "First test pass" do
        it "passes" do
            myvar = 20
            expect(myvar).to eq(20)
        end
    end

    context "Second test pass" do
        it "passes" do
            expect(myvar).to eq(20)
        end
    end
end

Now, obviously, this will not work with let because with new context, myvar variable will be back on initial state which is = 0. I would need mechanism to "cache state" between two contexts which would in turn give me value of myvar = 20 in second context

Any opinions, suggestions and improvements are welcome. Thanks

like image 700
Bakir Jusufbegovic Avatar asked Feb 11 '23 09:02

Bakir Jusufbegovic


2 Answers

Another simple way, would be to define a 'local variable' in describe context. the 'local variable' would live throughout the describe, and any changes during run time would effect it, and so change it.

For example

describe 'tests' do
    context 'Sharing a variable across tests' do
        var = 1
        puts var

        it "it one. var = #{var}" do
            var = var*2
            puts var
        end
        it "it two" do
            puts var
        end
    end
end 

Output

1
2
1
like image 83
Rony G Avatar answered Feb 13 '23 21:02

Rony G


  1. What happens is not what you think happens.
  2. What you want to happen break "unit testing" as a methodology.

Let me explain #2 first - unit testing test cases should be able to work in isolation, which means that they should work when run together, when run apart, and in any order... so much so that some unit testing frameworks (like the default one in elixir) run test cases in parallel...

As for #1 - when you write myvar = 20 you are not assigning a value to let(:myvar) { @myvar = 0 }, you simply create a local variable, which will override all calls to myvar within the method, but will not be available outside the method (myvar will return 0).

Even if you would have set @myvar = 20 (unless you do it before you call myvar for the first time) instead, myvar would still return 0, since the let function is using a memento pattern, which means it is called once, and subsequent calls return the value originally returned (in this case 0):

puts myvar
@myvar = 20
puts myvar

# => 0
# => 0
like image 39
Uri Agassi Avatar answered Feb 13 '23 23:02

Uri Agassi