MiniTest에서 어떻게 스텁을 수행합니까?
내 테스트 내에서 클래스의 모든 인스턴스에 대해 미리 준비된 응답을 스텁하고 싶습니다.
다음과 같이 보일 수 있습니다.
Book.stubs(:title).any_instance().returns("War and Peace")
그러면 내가 부를 때마다 @book.title
"전쟁과 평화"를 반환합니다.
MiniTest 내에서이를 수행하는 방법이 있습니까? 그렇다면 예제 코드 스 니펫을 제공 할 수 있습니까?
아니면 모카 같은 게 필요한가요?
MiniTest는 Mocks를 지원하지만 Mocks는 내가 필요한 것에 대해 과잉입니다.
# 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
모의 라이브러리가없는 간단한 스터 빙에 흥미가 있다면 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
클래스의 모든 인스턴스를 스터 빙하는 것과 같이 좀 더 복잡한 것을 원한다면, 그렇게하는 것도 충분히 쉽습니다. 약간의 창의력을 발휘하면됩니다.
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
모든 Gems 테스트에 minitest를 사용하지만 mocha로 모든 stub을 수행합니다. Mocks로 모든 작업을 수행 할 수 있습니다. 도움이된다면 훌륭합니다.
require 'mocha'
Books.any_instance.stubs(:title).returns("War and Peace")
.NET에서 메서드를 쉽게 스텁 할 수 있습니다 MiniTest
. 정보는 github 에서 확인할 수 있습니다 .
따라서 예제를 따르고 Minitest::Spec
스타일을 사용하여 메서드를 스텁하는 방법입니다.
# - 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
이것은 정말 어리석은 예이지만 적어도 원하는 일을 수행하는 방법에 대한 단서를 제공합니다. Ruby 1.9 와 함께 제공되는 번들 버전 인 MiniTest v2.5.1 을 사용하여 시도 했는데이 버전에서는 #stub 메서드가 아직 지원되지 않는 것처럼 보였지만 MiniTest v3.0으로 시도했는데 매력처럼 작동했습니다.
행운을 빕니다. MiniTest 사용을 축하 드립니다 !
편집 : 이것에 대한 또 다른 접근 방식이 있으며 약간 해커처럼 보이지만 여전히 문제에 대한 해결책입니다.
klass = Class.new Book do
define_method(:title) { "War and Peace" }
end
klass.new.title.must_equal "War and Peace"
Minitest로는 이것을 할 수 없습니다. 그러나 특정 인스턴스를 스텁 할 수 있습니다.
book = Book.new
book.stub(:title, 'War and Peace') do
assert_equal 'War and Peace', book.title
end
@panic 의 대답 을 더 설명하기 위해 Book 클래스가 있다고 가정 해 보겠습니다.
require 'minitest/mock'
class Book; end
먼저 Book 인스턴스 스텁을 만들고 원하는 제목을 반환하도록합니다 (횟수 제한 없음).
book_instance_stub = Minitest::Mock.new
def book_instance_stub.title
desired_title = 'War and Peace'
return_value = desired_title
return_value
end
그런 다음 Book 클래스가 Book 인스턴스 스텁을 인스턴스화하도록합니다 (다음 코드 블록 내에서만 항상).
method_to_redefine = :new
return_value = book_instance_stub
Book.stub method_to_redefine, return_value do
...
이 코드 블록 내에서만 Book::new
메서드가 스텁됩니다. 해 보자:
...
some_book = Book.new
another_book = Book.new
puts some_book.title #=> "War and Peace"
end
또는 가장 간결하게 :
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
또는 Minitest 확장 gem을 설치할 수 있습니다 minitest-stub_any_instance
. (참고 :이 방법을 사용할 Book#title
때는 스텁하기 전에 메서드가 있어야합니다.) 이제 더 간단하게 말할 수 있습니다.
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
Book#title
특정 횟수만큼 호출 되었는지 확인하려면 다음을 수행하십시오.
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
따라서 특정 인스턴스에 대해 지정된 것보다 더 많이 stubbed 메서드를 호출하면 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.
You can always create a module in your test code, and use include or extend to monkey-patch classes or objects with it. eg (in book_test.rb)
module BookStub
def title
"War and Peace"
end
end
Now you can use it in your tests
describe 'Book' do
#change title for all books
before do
Book.include BookStub
end
end
#or use it in an individual instance
it 'must be War and Peace' do
b=Book.new
b.extend BookStub
b.title.must_equal 'War and Peace'
end
This allows you to put together more complex behaviours than a simple stub might allow
I thought I'd share an example that I built upon the answers here.
I needed to stub a method at the end of a long chain of methods. It all started with a new instance of a PayPal API wrapper. The call I needed to stub was essentially:
paypal_api = PayPal::API.new
response = paypal_api.make_payment
response.entries[0].details.payment.amount
I created a class that returned itself unless the method was amount
:
paypal_api = Class.new.tap do |c|
def c.method_missing(method, *_)
method == :amount ? 1.25 : self
end
end
Then I stubbed it in to PayPal::API
:
PayPal::API.stub :new, paypal_api do
get '/paypal_payment', amount: 1.25
assert_equal 1.25, payments.last.amount
end
You could make this work for more than just one method by making a hash and returning hash.key?(method) ? hash[method] : self
.
참고URL : https://stackoverflow.com/questions/7211086/how-do-i-stub-things-in-minitest
'developer tip' 카테고리의 다른 글
Ruby에서“잘못된 인수 개수 (0은 1)”가 무엇을 의미합니까? (0) | 2020.12.08 |
---|---|
Firebase 연결이 끊어 지거나 회복되었는지 감지 (0) | 2020.12.08 |
토스트에 이미지를 추가 하시겠습니까? (0) | 2020.12.07 |
CSS 표시 : 인라인 블록이 여백 상단을 허용하지 않습니까? (0) | 2020.12.07 |
[NSDate date]로 현재 날짜 및 시간 가져 오기 (0) | 2020.12.07 |