[rspec-users] rspec 1 - nested examples (in an each block) use the final block variable 4 times instead of each of the 4 once

Ashley Moran ashley.moran at patchspace.co.uk
Sat Jul 31 03:48:01 EDT 2010

On 31 Jul 2010, at 2:08 AM, nruth wrote:

> If I want to set up a context to run some examples in (models created
> with machinist, associations, etc) then the before block makes it
> clear that that's the state the examples are running against, and the
> @vars give me a (quick and dirty?) hook to refer back to parts of that
> setup (e.g. associated models) in the spec examples.
> Of course, this can be done with let as well, but since they are lazy-
> evaluated you can end up with your examples running in the wrong
> context. For example: http://gist.github.com/501517

Hi Nick

I've been bitten by that too :)  However, RSpec 2 comes to the rescue with `let!`, which evaluates the block immediately, so you don't have to call the method to get it evaluated.

It's interesting though, I'll have to sit down some time and think through what the semantics of `before`, `let` and `let!` mean to me...

> back to op briefly, I ended up with this approach for the specs
> instead:
>  describe "#add_question_set_of_type('Abstract Reasoning')" do
>    let(:subtest) {'Abstract Reasoning'}
>    it_should_behave_like "adding a question set"
>  end
>  describe "#add_question_set_of_type('Decision Analysis')" do
>    let(:subtest) {'Decision Analysis'}
>    it_should_behave_like "adding a question set"
>  end
> etc…
> perhaps not ideal if another test is added in later, and I wanted
> coverage of that too for free, but it avoided the immediate problem &
> is more clear what's going on.

Hmm, without seeing the rest of your code it's hard to say, but this looks like a case of Control Couple.  Is there a case statement inside?  If not is there any reason not to have methods #add_abstract_reasoning_question_set, #add_decision_analysis_question_set?  If you're not branching on the parameter, how does the different behaviour come about?

> I certainly prefer let and subject to @vars for shared examples -
> again both work, but I find subject & lets provide a clear interface
> for the shared example groups which I felt was lacking when passing
> @variables around.

I agree.  I'm going to see if I can tighten this up today with a DSL to explicitly name the requirements of a shared example.  (See the thread "Evaluating shared example customisation block before shared block".)

> Re: error / warning message, at the same scope (i.e. an accident, as
> in the op) then yes that could be quite useful for spotting mistakes.
> I'm not so sure about in different blocks though, it's probably
> intentional there (different context).
> Re: redefining vs refactoring - I like what you're saying (reminds me
> of dry vs non-dry specs, and I find myself refactoring a lot of my old
> spaghetti specs lately), but wonder if there are (edge) cases where
> it's useful or necessary. Maybe there's some discussion dating back to
> when the feature was added. It may be stylistic though, rather than
> enforceable?
> Re: LSP, food for thought, nothing to add at present unfortunately.
> Not sure what angle you're approaching shared examples from with that
> though, do you mean redefining lets inside of the shared example
> groups, or something else?

Redefining lets anywhere actually.  The case for doing it within an example group is probably stronger, as you wrote (or can manage) all the examples yourself.  I guess if RSpec raised an error when a shared example accidentally redefines something from the host group, that would be noise, and force you to change your own code unnecessarily.  Hopefully, if shared examples can say "I require these things to be set up", that issues won't arise.  We'll see :)



More information about the rspec-users mailing list