freerange / mocha

A mocking and stubbing library for Ruby

Home Page:https://mocha.jamesmead.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

undefined method `sequences'

tim-wovn opened this issue · comments

In trying to upgrade from mocha 2.1 to 2.2 I get an error that can be replicated with a simple example from the rails console:

require 'mocha/mock'

class Foo
end

foo_mock = Mocha::Mock.new(Foo)
foo_mock.stubs(:bar)

this will throw the error:

.../vendor/bundle/ruby/3.2.0/gems/mocha-2.2.0/lib/mocha/mock.rb:157:in `block in stubs': undefined method `sequences' for Foo:Class (NoMethodError)

        expectation.in_sequence(@mockery.sequences.last) if @mockery.sequences.any?

This change was introduced here:
https://github.com/freerange/mocha/pull/631/files#diff-55d8f4658c250f3420c3932cdbac3589f61634805788ae52be7eced862dae751R157

In my case Foo is a class provided by a 3rd party library. I'd like to avoid monkey patching in a sequences method although honestly its probably not a problem to do so. Did you have any thoughts on this situation?

Thank you for your work on this library!

@tim-wovn Thanks for reporting this. Just to clarify, is this problem specific to stubbing the #class method on a concrete class? Or just stubbing any method...?

Thanks for reporting this. Just to clarify, is this problem specific to stubbing the #class method on a concrete class? Or just stubbing any method...?

@floehopper Sorry, I should have been clearer. The example reflects my particular use case however, testing further, it seems that stubbing anything will trigger the error e.g. foo_mocks.stubs(:bar).

I've updated my example. 🙇

@tim-wovn

I've just tried reproducing this. I can only reproduce it by incorrectly using the Mocha::Mock#initialize method like you do in your example code:

require "bundler/setup"
require "minitest/autorun"
require 'mocha/minitest'
require 'mocha/mock'

class Foo; end

class FooTest < Minitest::Test
  def test_foo
    foo = Mocha::Mock.new(Foo)
    foo.stubs(:bar) # => NoMethodError: undefined method `sequences' for Foo:Class
  end
end

However, Mocha::Mock#initialize is not part of the public API, so you shouldn't be using it / relying on its behaviour. Also the first argument to Mocha::Mock#initialize is an instance of the internal Mocha::Mockery class and not the class the mock is replacing. Is the code you have posted representative of your actual code?

Changing the test to something more idiomatic works fine (no errors/failures):

  def test_foo
    foo = mock('Foo')
    foo.stubs(:bar)
  end

Note that the first argument to Mocha::API#mock must be a String or a Symbol (not a class).

Maybe you want something like Mocha::Mock#responds_like_instance_of?

I'm not really sure what you're trying to do and/or why it was working before the upgrade!

@floehopper Thank you for the investigation. After reading your explanation, I think we can close this issue as "user error". 🙇

For this particular use case, we've defined the mocks in some mock helper classes that are not tests themselves but are later used inside of our tests. Because of that, mock() is not defined, although extending the helper class with extend Mocha::API seems to do the trick.

(I do get some test failures but the failures seem legitimate--I'm not sure why the tests were passing before! 😨 )

Sorry for taking your time. Thank you again for investigating!

@tim-wovn No worries - thanks for getting back to me!