1

I have this method that I'm trying to test:

def build
    return if !cookies["__utmz"] && !cookies["__utma"]
    binding.pry
    @data = GaCookieParser::GaCookieParser.new(
      utmz: cookies["__utmz"],
      utma: cookies["__utma"]
    )
    build_utmz
    build_utma
    TrafficSource.new(params)
  end

This is my test:

context 'when cookies have necessary params' do
      let(:cookies) { complete_cookies }
      let(:complete_cookies) do
        {
          '__utmz' => 'something',
          '__utma' => 'something'
        }
      end

I used a let and when I hit the binding, "cookies" does indeed return me complete_cookies.

let is only supposed to "stub" the method inside the test right whereas allow will stub the method anywhere in the actual code right?

Jwan622
  • 11,015
  • 21
  • 88
  • 181

1 Answers1

3

let and allow do extremely different things. let is not a method stub... it's a way of creating test data/objects to manipulate in your tests.

a let is a nicer way of doing something like:

before do
   @cookies =  { '__utmz' => 'something', '__utma' => 'something' }
end

then having to use @cookies in your tests. It's better than instantiating things in before-blocks because it isn't instantiated until you actually use it - which reduces instantiation of objects that aren't used in all tests.

If you really want to stub a method, you must use a receives expectation eg:

allow(thing).to receive(:cookies).and_return(complete_cookies)
expect(thing).to receive(:cookies).and_return(complete_cookies)

The behaviour you're seeing is, I think, not what you're expecting... because what you've accidentally done is paper over the method cookies with a local variable called cookies...

Which is a bit dangerous and likely to be brittle. In this instance, I'd use an actual expect or allow on the object that contains the build method (which you haven't named in your example code above). That is the standard practice for what you seem to want to do. In that case, yes it will indeed stub over the method, as you expect it to.

Taryn East
  • 27,486
  • 9
  • 86
  • 108
  • 1
    Can you use 'allow' and expect interchangably? I thought allow was for stubbing and 'expect' was for testing that an object actually receives a method. https://www.relishapp.com/rspec/rspec-mocks/docs – Jwan622 Apr 12 '16 at 03:53
  • 1
    @Jwan622 You are right `allow` creates a stub while `expect` creates a mock. You will need to decide yourself which one suits your needs better. Here is a discussion on the matter [RSpec allow/expect vs just expect/and_return](http://stackoverflow.com/questions/28006913/rspec-allow-expect-vs-just-expect-and-return) and here is discussion on let [When to use rspec let()?](http://stackoverflow.com/questions/5359558/when-to-use-rspec-let) – Laura Paakkinen Apr 12 '16 at 06:00
  • Yes, you can't use them interchangably - use the one appropriate... however they are both closely related things (you are papering over a method and returning a value of your choosing), whereas a `let` is a very different thing to either. – Taryn East Apr 12 '16 at 06:04