How do I stub things in MiniTest?

前端 未结 8 913
面向向阳花
面向向阳花 2020-12-02 09:46

Within my test I want to stub a canned response for any instance of a class.

It might look like something like:

Book.stubs(:title).any_instance().ret         


        
8条回答
  •  鱼传尺愫
    2020-12-02 10:07

    Just to further explicate @panic's answer, let's assume you have a Book class:

    require 'minitest/mock'
    class Book; end
    

    First, create a Book instance stub, and make it return your desired title (any number of times):

    book_instance_stub = Minitest::Mock.new
    def book_instance_stub.title
      desired_title = 'War and Peace'
      return_value = desired_title
      return_value
    end
    

    Then, make the Book class instantiate your Book instance stub (only and always, within the following code block):

    method_to_redefine = :new
    return_value = book_instance_stub
    Book.stub method_to_redefine, return_value do
      ...
    

    Within this code block (only), the Book::new method is stubbed. Let's try it:

      ...
      some_book = Book.new
      another_book = Book.new
      puts some_book.title #=> "War and Peace"
    end
    

    Or, most tersely:

    require 'minitest/mock'
    class Book; end
    instance = Minitest::Mock.new
    def instance.title() 'War and Peace' end
    Book.stub :new, instance do
      book = Book.new
      another_book = Book.new
      puts book.title #=> "War and Peace"
    end
    

    Alternatively, you can install the Minitest extension gem minitest-stub_any_instance. (Note: when using this approach, the Book#title method must exist before you stub it.) Now, you can say more simply:

    require 'minitest/stub_any_instance'
    class Book; def title() end end
    desired_title = 'War and Peace'
    Book.stub_any_instance :title, desired_title do
      book = Book.new
      another_book = Book.new
      puts book.title #=> "War and Peace"
    end
    

    If you want to verify that Book#title is invoked a certain number of times, then do:

    require 'minitest/mock'
    class Book; end
    
    book_instance_stub = Minitest::Mock.new
    method = :title
    desired_title = 'War and Peace'
    return_value = desired_title
    number_of_title_invocations = 2
    number_of_title_invocations.times do
      book_instance_stub.expect method, return_value
    end
    
    method_to_redefine = :new
    return_value = book_instance_stub
    Book.stub method_to_redefine, return_value do
      some_book = Book.new
      puts some_book.title #=> "War and Peace"
    # And again:
      puts some_book.title #=> "War and Peace"
    end
    book_instance_stub.verify
    

    Thus, for any particular instance, invoking the stubbed method more times than specified raises MockExpectationError: No more expects available.

    Also, for any particular instance, having invoked the stubbed method fewer times than specified raises MockExpectationError: expected title(), but only if you invoke #verify on that instance at that point.

提交回复
热议问题