MTJ Hax

MiniTest version of RSpec any_instance

Posted in code, ruby, ruby on rails by mtjhax on August 30, 2013

Using MiniTest in Rails apps, I have been missing the RSpec any_instance method:

MyClass.any_instance.stubs(:a_method)

There are other ways to stub in MiniTest but any_instance is convenient and expressive, so I wrote my own quickie version based on aliasing. I call it all_instances to avoid any problems if also using RSpec. Drop this in a file in test/support and make sure it is included in your test_helper.rb:

# this allows a MiniTest test to stub out a method on all instances of a class
# examples:
#
# MyClass.all_instances.stub(:foo, 'bar') do
#   MyClass.new.foo.must_equal 'bar'
# end
#
# MyClass.all_instances.stub(:foo, 'bar')
# MyClass.new.foo.must_equal 'bar'
# MyClass.all_instances.unstub(:foo, 'bar')

class AllInstances
  def initialize(klass)
    @klass = klass
    @@new_method_names ||= {}
  end

  def stub(method_name, return_value)
    @@new_method_names[method_name] = "_original_#{method_name}".to_sym
    @klass.send(:alias_method, @@new_method_names[method_name], method_name)
    @klass.send(:define_method, method_name, ->(*args){ return_value })
    if block_given?
      begin
        yield
      ensure
        unstub(method_name)
      end
    end
  end

  def unstub(method_name)
    @klass.send(:remove_method, method_name)
    @klass.send(:alias_method, method_name, @@new_method_names[method_name])
    @@new_method_names[method_name] = nil
  end
end

class Class
  def all_instances
    AllInstances.new(self)
  end
end
Advertisements

One Response

Subscribe to comments with RSS.

  1. mtjhax said, on January 1, 2014 at 7:56 pm

    Not sure how I wasn’t aware of this, but Mocha (http://gofreerange.com/mocha/docs/) integrates with MiniTest and provides any_instance mocking and stubbing. My little snippet is still useful if you want this sort of feature and don’t want to use Mocha (not sure why not, Mocha is pretty sweet).


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: