[rspec-devel] [ rspec-Bugs-11091 ] mock setup fails in before(:all), but succeeds in before(:each)

noreply at rubyforge.org noreply at rubyforge.org
Thu May 24 11:31:14 EDT 2007


Bugs item #11091, was opened at 2007-05-24 11:26
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=11091&group_id=797

Category: mock module
Group: None
Status: Closed
Resolution: Rejected
Priority: 3
Submitted By: Jon Egil Strand (jonegil)
Assigned to: David Chelimsky (dchelimsky)
Summary: mock setup fails in before(:all), but succeeds in before(:each)

Initial Comment:


The attached spec shows how setting up a mock fails inconsistently.

When setting it up within before(:all), it fails.
When setting it up within before(:each), it is ok.
When setting it up within before(:each), then within before(:all), both are ok.


Parsing data
- before(:all) (ERROR - 1)

Parsing data
- should include 10 persons (ERROR - 2)

Parsing data
- should include 10 persons (ERROR - 3)

1)
NoMethodError in 'Parsing data before(:all)'
undefined method `add' for nil:NilClass
./test\spec_bug.rb:5:

2)
Spec::Mocks::MockExpectationError in 'Parsing data should include 10 persons'
Mock 'gui' expected :increment with (any args) once, but received it 0 times
./test\spec_bug.rb:18:

3)
Spec::Mocks::MockExpectationError in 'Parsing data should include 10 persons'
Mock 'gui' expected :increment with (any args) once, but received it 0 times
./test\spec_bug.rb:31:

Finished in 0.06 seconds

3 examples, 3 failures

----------------------------------------------------------------------

>Comment By: David Chelimsky (dchelimsky)
Date: 2007-05-24 15:31

Message:
Jon - you cite an interesting case, but a problematic one as well.

The philosophical problem is that "log.should_receive(:informative_message).once" sets an expectation, but it is not part of any example, which means that you lose the documentation value (i.e. it is never expressed in any report).

The practical problem is that mocks and stubs get torn down implicitly after(:each) example. This means that should_receive will be effective in the first example that is run, but not in the second.

So in this case, if all you need is stubs, you could use something like openstruct:

require 'ostruct'

describe "Heavy parser process" do
  before(:all) do
    log = OpenStruct.new(:informative_message => true)
    @heavy = HeavyParser.new('path/to/data', log)    
  end
  
... and then if you really want to set a mock expectation to express a requirement
that something gets logged, you can do THAT like this:

  it "should receive an informative message"
    @heavy.log.
      should_receive(:informative_message).
      with("very informative")
    @heavy.parse(something)
  end
  
end


----------------------------------------------------------------------

Comment By: Aslak Hellesøy (aslak_hellesoy)
Date: 2007-05-24 13:56

Message:
Perhaps mock() should not even be available in the before(:all) block? Or - it could be available, but raise an error with a good explanation.

----------------------------------------------------------------------

Comment By: Jon Egil Strand (jonegil)
Date: 2007-05-24 13:08

Message:
Not meaning to make this an open discussion, but actually,
before(:all) mocks are more of a yes-yes than a no-no.

I set this thing up as follows: 

describe "Heavy parser process" do
  before(:all) do
    log = mock("log")
    log.should_receive(:informative_message).once
    #Let's say this is a very slow (1 minute) process
    @heavy = HeavyParser.new('path/to/data', log)    
  end

  it "should contain expected data" do
    @heavy.data.should include(:expected)
  end

  it "should not contain surprises" do
    @heavy.data.should_not include(:surprise)
  end
end


Since the before(:all) is _slow_ I like to be able to do it
just once. Am I missing out on something?


----------------------------------------------------------------------

Comment By: David Chelimsky (dchelimsky)
Date: 2007-05-24 11:41

Message:
This is by design. before(:all) is not executed in the same binding as the examples are. 

Using before(:all) for mocks is a mock-no-no. Doing so would bind your examples together and produce unexpected results.

What we need is better documentation about before(:each) and before(:all). I'll work on that for the next release.

----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=3149&aid=11091&group_id=797


More information about the rspec-devel mailing list