1
votes

It said here https://www.relishapp.com/rspec/rspec-core/v/3-5/docs/helper-methods/let-and-let what variable defined by let is changing across examples. I've made the same simple test as in the docs but with the AR model:

RSpec.describe Contact, type: :model do
  let(:contact) { FactoryGirl.create(:contact) }

  it "cached in the same example" do
    a = contact
    b = contact
    expect(a).to eq(b)
    expect(Contact.count).to eq(1)
  end

  it "not cached across examples" do
    a = contact
    expect(Contact.count).to eq(2)
  end
end

First example passed, but second failed (expected 2, got 1). So contacts table is empty again before second example, inspite of docs.

I was using let and was sure it have the same value in each it block, and my test prove it. So suppose I misunderstand docs. Please explain.

P.S. I use DatabaseCleaner P.P.S I turn it off. Nothing changed.

EDIT I turned off DatabaseCleaner and transational fixtures and test pass. As I can understand (new to programming), let is evaluated once for each it block. If I have three examples each calling on contact variable, my test db will grow to three records at the end (I've tested and so it does). And for right test behevior I should use DatabaseCleaner.

2
RE "I turn it off" - do you also have transactional fixtures on?Sergio Tulentsev
Also, could you elaborate, why exactly you expect two contacts in the second example?Sergio Tulentsev
The behaviour you have shown is the correct behaviour - you shouldn't be trying to cache across examples. No example should be dependant on another example setting up the correct environment!David
I really new to rails. I take the example from docs and redo it with AR. And test doesn't pass. So I get two similar test with different result.fomkin
that may be ... but that isn't the behaviour you want. you are just asking for trouble later down the line. And yes as sergio pointed out that example is demonstrating something completely different and making use of a global variable to demonstrate it.David

2 Answers

1
votes

P.S. I use DatabaseCleaner

That's why your database is empty in the second example. Has nothing to do with let.

1
votes

The behaviour you have shown is the correct behaviour. No example should be dependant on another example in setting up the correct environment! If you did rely on caching then you are just asking for trouble later down the line.

The example in that document is just trying to prove a point about caching using global variables - it's a completely different scenario to unit testing a Rails application - it is not good practice to be reliant on previous examples to having set something up.

Lets, for example, assume you then write 10 other tests that follow on from this, all of which rely on the fact that the previous examples have created objects. Then at some point in the future you delete one of those examples ... BOOM! every test after that will suddenly fail.

Each test should be able to be tested in isolation from any other test!