On 9/5/06, John Wilger <johnwilger / gmail.com> wrote:
> For the unit tests, I'm using FlexMock to stub out the calls to import
> in the other classes. If I run a single test case using `ruby
> test/unit/my_test_file.rb`, everything works as expected. However,
> when I try to run the whole test suite using `rake` (this is a Rails
> app, BTW), I start to see a lot of errors like this:

>  16) Error:
> test_should_return_status_if_it_exists(StatusTest::Import):
> NoMethodError: undefined method `import' for #<FlexMock:0x236a0e0>

> It looks like the FlexMock::TestCase#flexmock_teardown method is
> removing the stub for Status.import, but it isn't restoring the
> original method.

Bad form replying to myself, I know -- but I think I figured out
what's going on...

In my tests, I've been been doing this:

  class MyTest < Test::Unit::TestCase
    include FlexMock::TestCase

    def setup
      # set up a default stub
      flexstub( SomeClass ).should_receive( :foo )
    end

    def test_method_that_calls_foo_but_not_interested_in_foo_a
      SomeOtherClass.do_something_that_calls_foo
      # other assertions, etc
    end

    def test_method_that_calls_foo_but_not_interested_in_foo_b
      SomeOtherClass.do_something_that_calls_foo
      # other assertions, etc
    end

    def test_method_that_calls_foo_and_cares
      flexstub( SomeClass ).should_receive( :foo ).once.with( :bar )
      SomeOtherClass.do_something_that_calls_foo
    end
  end

So, I want to be able to set up a default stub for SomeClass.foo, so
that I can test SomeOtherClass.do_something_that_calls_foo without
using the actual implimentation of SomeClass.foo, but I don't want to
have to write that default stub out in each test method.

The problem is that when test_method_that_calls_foo_and_cares is run,
it thinks the default stub is the _original_ method, and when the test
is finished running, it's the default stub method that ends up being
restored.

In order to make this work, we just need to make sure that the
original method isn't overwritten if we make more than one call to
#should_receive for a particular stub. It's a pretty simple change on
line 1008 of lib/flexmock.rb. Just change:

  @method_definitions[method_name] = @obj.method(method_name)

to:

  @method_definitions[method_name] ||= @obj.method(method_name)

All existing unit tests for the FlexMock library still pass with that
change in place (though I've not yet written any tests to cover this
case), _and_ it solves the problem I was having with FlexMock in my
own application.

-- 
Regards,
John Wilger
http://johnwilger.com

-----------
Alice came to a fork in the road. "Which road do I take?" she asked.
"Where do you want to go?" responded the Cheshire cat.
"I don't know," Alice answered.
"Then," said the cat, "it doesn't matter."
- Lewis Carrol, Alice in Wonderland