mock method allow ruby unit-testing rspec rspec-mocks

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