How do I stub things in MiniTest?
# Create a mock object book = MiniTest::Mock.new # Set the mock to expect :title, return "War and Piece" # (note that unless we call book.verify, minitest will # not check that :title was called) book.expect :title, "War and Piece" # Stub Book.new to return the mock object # (only within the scope of the block) Book.stub :new, book do wp = Book.new # returns the mock object wp.title # => "War and Piece" end
I use minitest for all my Gems testing, but do all my stubs with mocha, it might be possible to do all in minitest with Mocks(there is no stubs or anything else, but mocks are pretty powerful), but I find mocha does a great job, if it helps:
require 'mocha' Books.any_instance.stubs(:title).returns("War and Peace")
If you're interesting in simple stubbing without a mocking library, then it's easy enough to do this in Ruby:
class Book def avg_word_count_per_page arr = word_counts_per_page sum = arr.inject(0) { |s,n| s += n } len = arr.size sum.to_f / len end def word_counts_per_page # ... perhaps this is super time-consuming ... endenddescribe Book do describe '#avg_word_count_per_page' do it "returns the right thing" do book = Book.new # a stub is just a redefinition of the method, nothing more def book.word_counts_per_page; [1, 3, 5, 4, 8]; end book.avg_word_count_per_page.must_equal 4.2 end endend
If you want something more complicated like stubbing all instances of a class, then it is also easy enough to do, you just have to get a little creative:
class Book def self.find_all_short_and_unread repo = BookRepository.new repo.find_all_short_and_unread endenddescribe Book do describe '.find_all_short_unread' do before do # exploit Ruby's constant lookup mechanism # when BookRepository is referenced in Book.find_all_short_and_unread # then this class will be used instead of the real BookRepository Book.send(:const_set, BookRepository, fake_book_repository_class) end after do # clean up after ourselves so future tests will not be affected Book.send(:remove_const, :BookRepository) end let(:fake_book_repository_class) do Class.new(BookRepository) end it "returns the right thing" do # Stub #initialize instead of .new so we have access to the # BookRepository instance fake_book_repository_class.send(:define_method, :initialize) do super def self.find_all_short_and_unread; [:book1, :book2]; end end Book.find_all_short_and_unread.must_equal [:book1, :book2] end endend