ruby - method - rspec mock object
Ejemplo de objeto falso RSpec (5)
Aquí hay un ejemplo de un simple simulacro que hice para una prueba de controlador en una aplicación de rieles:
before(:each) do
@page = mock_model(Page)
@page.stub!(:path)
@page.stub!(:find_by_id)
@page_type = mock_model(PageType)
@page_type.stub!(:name)
@page.stub!(:page_type).and_return(@page_type)
end
En este caso, me burlo de los modelos Page y PageType (Objetos) y corto algunos de los métodos que llamo.
Esto me da la posibilidad de ejecutar pruebas como esta:
it "should be successful" do
Page.should_receive(:find_by_id).and_return(@page)
get ''show'', :id => 1
response.should be_success
end
Sé que esta respuesta es más específica para los rieles, pero espero que te ayude un poco.
Editar
Bien, entonces aquí hay un ejemplo de Hello World ...
Dado el siguiente script (hello.rb):
class Hello
def say
"hello world"
end
end
Podemos crear la siguiente especificación (hello_spec.rb):
require ''rubygems''
require ''spec''
require File.dirname(__FILE__) + ''/hello.rb''
describe Hello do
context "saying hello" do
before(:each) do
@hello = mock(Hello)
@hello.stub!(:say).and_return("hello world")
end
it "#say should return hello world" do
@hello.should_receive(:say).and_return("hello world")
answer = @hello.say
answer.should match("hello world")
end
end
end
Soy nuevo para simular objetos, y estoy tratando de aprender a usarlos en RSpec. ¿Puede alguien publicar un ejemplo (un ejemplo de hello RSpec Mock object world type), o un enlace (o cualquier otra referencia) sobre cómo usar el objeto RSpec simulado API?
La RSpec actual (3.x) proporciona tanto objetos simulados puros (como en la respuesta de tokhi ) como burlas parciales (llamadas burlonas a un objeto existente). Aquí hay un ejemplo de burla parcial. Utiliza expect
y receive
para CreditCardService
una llamada de una CreditCardService
a un CreditCardService
, de modo que la prueba solo se transmita si la llamada se realiza sin tener que realizarla.
class Order
def cancel
CreditCardService.instance.refund transaction_id
end
end
describe Order do
describe ''#cancel'' do
it "refunds the money" do
order = Order.new
order.transaction_id = "transaction_id"
expect(CreditCardService.instance).to receive(:refund).with("transaction_id")
order.cancel
end
end
end
En este ejemplo, el simulacro está en el valor de retorno de CreditCardService.instance
, que presumiblemente es un singleton.
with
es opcional; sin él, cualquier llamada a refund
satisfaría las expectativas. Se podría dar un valor de retorno con and_return
; en este ejemplo, no se usa, por lo que la llamada devuelve nil
.
Este ejemplo utiliza la sintaxis de burla actual ( expect .to receive
) de RSpec, que funciona con cualquier objeto. La respuesta aceptada usa el antiguo método rspec-rails mock_model
, que era específico para los modelos ActiveModel y se movió fuera de rspec-rails a otra gema.
No tengo suficientes puntos para publicar un comentario en una respuesta, pero quería decir que la respuesta aceptada también me ayudó a tratar de encontrar la forma de un valor aleatorio.
Necesitaba poder resguardar el valor de instancia de un objeto que se asigna aleatoriamente, por ejemplo:
class ClumsyPlayer < Player do
def initialize(name, health = 100)
super(name, health)
@health_boost = rand(1..10)
end
end
Luego, en mi especificación, tuve un problema para encontrar la forma de proteger la salud aleatoria del jugador torpe para probar que cuando obtienen una curación, obtienen el impulso adecuado para su salud.
El truco fue:
@player.stub!(health_boost: 5)
Entonces ese stub!
era la clave, solo había estado usando stub
y seguía obteniendo pases y fallas de rspec al azar.
Así que gracias Brian
Normalmente desea utilizar un objeto simulado cuando desea delegar alguna funcionalidad a otro objeto pero no desea probar la funcionalidad real en su prueba actual, por lo que reemplaza ese objeto por otro que sea más fácil de controlar. Llamemos a este objeto "dependencia" ...
Lo que está probando (objeto / método / función ...) puede interactuar con esta dependencia llamando a métodos para ...
- Pregunta por algo
- Cambie algo o produzca algún efecto secundario.
Cuando se llama a un método para buscar algo
Cuando usa la dependencia para "consultar" algo, no necesita usar la "API simulada" porque puede usar un objeto normal y probar el resultado esperado en el objeto que está probando ... por ejemplo:
describe "Books catalog" do
class FakeDB
def initialize(books:)
@books = books
end
def fetch_books
@books
end
end
it "has the stored books" do
db = FakeDB.new(books: ["Principito"])
catalog = BooksCatalog.new(db)
expect(catalog.books).to eq ["Principito"]
end
end
Cuando llamas a un método para cambiar algo o producir algún efecto secundario ...
Cuando desee realizar un cambio en su dependencia o hacer algo con efectos secundarios como insertar un nuevo registro en una base de datos, enviar un correo electrónico, realizar un pago, etc. ahora, en lugar de probar que se produjo el cambio o efecto secundario, simplemente comprueba que está llamando a la función / método correcto con los atributos correctos ... por ejemplo:
describe "Books catalog" do
class FakeDB
def self.insert(book)
end
end
def db
FakeDB
end
it "stores new added books" do
catalog = BooksCatalog.new(db)
# This is how you can use the Mock API of rspec
expect(db).to receive(:insert).with("Harry Potter")
catalog.add_book("Harry Potter")
end
end
Este es un ejemplo básico, pero puedes hacer mucho solo con este conocimiento =)
mock
está en desuso en función de este pull github.
Ahora, en cambio, podemos usar double
- más here...
before(:each) do
@page = double("Page")
end
it "page should return hello world" do
allow(@page).to receive(:say).and_return("hello world")
answer = @page.say
expect(answer).to eq("hello world")
end