64 votes

Comment puis-je stub des choses dans MiniTest?

Dans le cadre de mon test, je souhaite remplacer une réponse prédéfinie pour toute instance d'une classe.

Cela pourrait ressembler à quelque chose comme:

 Book.stubs(:title).any_instance().returns("War and Peace")
 

Puis, chaque fois que j'appelle @book.title cela renvoie "Guerre et paix".

Y a-t-il un moyen de faire cela dans MiniTest? Si oui, pouvez-vous me donner un exemple d'extrait de code?

Ou ai-je besoin de quelque chose comme du moka?

MiniTest prend en charge Mocks, mais Mocks est excessif pour ce dont j'ai besoin.

40voto

Panic Points 191
  book = MiniTest::Mock.new
  book.expect :title, "War and Piece"

  Book.stub :new, book do
    wp = Book.new
    wp.title # => "War and Piece"
  end

28voto

daniel Points 5467

J'utilise minitest pour tous mes tests sur Gems, mais pour tous mes stubs avec du moka, il serait peut-être possible de faire tous les tests avec mocks (il n'y a pas de stubs ou autre chose, mais les mocks sont assez puissants), mais je trouve que moka excellent travail, si cela aide:

 require 'mocha'    
Books.any_instance.stubs(:title).returns("War and Peace")
 

26voto

Elliot Winkler Points 1141

Si vous êtes intéressé par une simple manipulation sans bibliothèque moqueuse, il est assez facile de le faire en 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 ...
  end
end

describe 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
  end
end
 

Si vous voulez quelque chose de plus compliqué que de remplacer toutes les occurrences d'une classe, c'est aussi assez facile à faire, il vous suffit de faire un peu de créativité:

 class Book
  def self.find_all_short_and_unread
    repo = BookRepository.new
    repo.find_all_short_and_unread
  end
end

describe 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
  end
end
 

22voto

mongrelion Points 158

Vous pouvez facilement stub méthodes de MiniTest. L'information est disponible sur github.

Donc, en suivant votre exemple, et en utilisant le Minitest::Spec style, c'est la façon dont vous devriez stub méthodes:

# - RSpec -
Book.stubs(:title).any_instance.returns("War and Peace")

# - MiniTest - #
Book.stub :title, "War and Peace" do
  book = Book.new
  book.title.must_equal "War and Peace"
end

Ce vraiment un exemple stupide, mais au moins vous donne un indice sur la façon de faire ce que vous voulez faire. J'ai essayé cette aide MiniTest v2.5.1 qui est le lot de la version qui vient avec Ruby 1.9 et il semble que dans cette version le #stub la méthode n'est pas encore pris en charge, mais ensuite j'ai essayé avec MiniTest v3.0 et il a travaillé comme un charme.

Bonne chance et félicitations à l'aide de MiniTest!

Edit: Il existe aussi une autre approche pour cela, et même si ça semble un peu hackish, c'est toujours une solution à votre problème:

klass = Class.new Book do
  define_method(:title) { "War and Peace" }
end

klass.new.title.must_equal "War and Peace"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X