ruby - prender - encender pantalla iphone 5 sin boton
¿Cómo apago cosas en MiniTest? (8)
No puedes hacer esto con Minitest. Sin embargo, puede apilar cualquier instancia particular:
book = Book.new
book.stub(:title, ''War and Peace'') do
assert_equal ''War and Peace'', book.title
end
Dentro de mi prueba, quiero resaltar una respuesta enlatada para cualquier instancia de una clase.
Puede parecer algo como:
Book.stubs(:title).any_instance().returns("War and Peace")
Luego, cada vez que llamo a @book.title
devuelve "Guerra y paz".
¿Hay una manera de hacer esto dentro de MiniTest? Si es así, ¿puedes darme un fragmento de código de ejemplo?
¿O necesito algo como mocha?
MiniTest admite Mocks pero las mocks son excesivas por lo que necesito.
Pensé que compartiría un ejemplo que construí sobre las respuestas aquí.
Necesitaba quitar un método al final de una larga cadena de métodos. Todo comenzó con una nueva instancia de un contenedor de API de PayPal. La llamada que necesitaba para stub era esencialmente:
paypal_api = PayPal::API.new
response = paypal_api.make_payment
response.entries[0].details.payment.amount
Creé una clase que se devolvía a sí misma a menos que el método fuera amount
paypal_api = Class.new.tap do |c|
def c.method_missing(method, *_)
method == :amount ? 1.25 : self
end
end
Luego lo apagué en PayPal::API
:
PayPal::API.stub :new, paypal_api do
get ''/paypal_payment'', amount: 1.25
assert_equal 1.25, payments.last.amount
end
¿Podría hacer que esto funcione para más de un método haciendo un hash y devolviendo hash.key?(method) ? hash[method] : self
hash.key?(method) ? hash[method] : self
.
Si estás interesado en un simple stubbing sin una biblioteca burlona, entonces es bastante fácil hacer esto 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 quieres algo más complicado como aplastar todas las instancias de una clase, entonces también es bastante fácil de hacer, solo tienes que ser un poco creativo:
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
Siempre puede crear un módulo en su código de prueba, y usar incluir o extender a las clases u objetos de mono-parche con él. por ejemplo (en book_test.rb)
module BookStub
def title
"War and Peace"
end
end
Ahora puedes usarlo en tus pruebas.
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
Esto le permite armar comportamientos más complejos de lo que un simple código auxiliar podría permitir
Solo para explicar con más detalle la respuesta de @pánico , supongamos que tienes una clase de Libro:
require ''minitest/mock''
class Book; end
Primero, cree un talón de instancia de Libro y haga que devuelva el título deseado (cualquier número de veces):
book_instance_stub = Minitest::Mock.new
def book_instance_stub.title
desired_title = ''War and Peace''
return_value = desired_title
return_value
end
Luego, haga que la clase Book ejemplifique su código auxiliar de instancia de Book (solo y siempre, dentro del siguiente bloque de código):
return_value = book_instance_stub
method_to_redefine = :new
Book.stub method_to_redefine, return_value do
...
Dentro de este bloque de código (solo), el método Book :: new se apaga. Vamos a intentarlo:
...
some_book = Book.new
another_book = Book.new
puts some_book.title #=> "War and Peace"
puts some_book.title #=> "War and Peace"
end
O, muy tersamente:
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"
puts book.title #=> "War and Peace"
end
Alternativamente, puede instalar la gema de la extensión Minitest ''minitest-stub_any_instance''. (Nota: utilizando este enfoque, el método del título del libro debe existir antes de que lo apague). Ahora, puede decir más simplemente:
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"
puts book.title #=> "War and Peace"
end
Si desea verificar que el título de Libro # se invoca un cierto número de veces, entonces haga lo siguiente:
require ''minitest/mock''
class Book; end
desired_title = ''War and Peace''
return_value = desired_title
method = :title
book_instance_stub = Minitest::Mock.new
number_of_title_invocations = 2
number_of_title_invocations.times do
book_instance_stub.expect method, return_value
end
return_value = book_instance_stub
method_to_redefine = :new
Book.stub method_to_redefine, return_value do
some_book = Book.new
puts some_book.title #=> "War and Peace"
puts some_book.title #=> "War and Peace"
end
book_instance_stub.verify
Por lo tanto, para cualquier instancia en particular, invocar el método MockExpectationError: No more expects available
más veces que las especificadas aumenta MockExpectationError: No more expects available
.
Además, para cualquier instancia en particular, invocar el método MockExpectationError: expected title()
menos veces de lo especificado genera MockExpectationError: expected title()
, pero solo si invoca #verify después en esa instancia.
Usted puede fácilmente MiniTest
métodos en MiniTest
. La información está disponible en github .
Entonces, siguiendo tu ejemplo y usando el estilo Minitest::Spec
, esta es la forma en que deberías aplastar los métodos:
# - 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
Este es un ejemplo realmente estúpido, pero al menos te da una pista sobre cómo hacer lo que quieres hacer. Intenté esto usando MiniTest v2.5.1, que es la versión incluida que viene con Ruby 1.9 y parece que en esta versión el método #stub aún no era compatible, pero luego lo intenté con MiniTest v3.0 y funcionó a la perfección .
¡Buena suerte y felicitaciones por usar MiniTest !
Edit: También hay otro enfoque para esto, y aunque parece un poco pirateado, sigue siendo una solución a tu problema:
klass = Class.new Book do
define_method(:title) { "War and Peace" }
end
klass.new.title.must_equal "War and Peace"
Utilizo minitest para todas mis pruebas de gemas, pero hago todos mis talones con mocha, podría ser posible hacerlo todo en minitest con simulacros (no hay talones ni nada más, pero los simulacros son bastante poderosos), pero creo que mocha hace Gran trabajo, si ayuda:
require ''mocha''
Books.any_instance.stubs(:title).returns("War and Peace")
book = MiniTest::Mock.new
book.expect :title, "War and Piece"
Book.stub :new, book do
wp = Book.new
wp.title # => "War and Piece"
end