Я новичок в подделке объектов, и я пытаюсь научиться их использовать в RSpec. Может кто-нибудь, пожалуйста, отправьте пример (привет приветственный пример типа объекта MPpec Mock) или ссылку (или любую другую ссылку) о том, как использовать API-интерфейс макетного объекта RSpec?
Пример RSock Mock Object
Ответ 1
Вот пример простого макета, который я сделал для теста контроллера в приложении rails:
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
В этом случае я издеваюсь над страницами и типами страниц (Objects), а также излагаю несколько методов, которые я вызываю.
Это дает мне возможность запускать тесты следующим образом:
it "should be successful" do
Page.should_receive(:find_by_id).and_return(@page)
get 'show', :id => 1
response.should be_success
end
Я знаю, что этот ответ больше специфичен для рельсов, но я надеюсь, что это поможет вам немного.
Edit
Итак, вот пример мира привет...
Учитывая следующее script (hello.rb):
class Hello
def say
"hello world"
end
end
Мы можем создать следующую спецификацию (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
Ответ 2
У меня недостаточно баллов, чтобы опубликовать комментарий к ответу, но я хотел сказать, что принятый ответ также помог мне разобраться, как заглушить случайное значение.
Мне нужно было иметь возможность заглушить значение экземпляра объекта, которое случайным образом назначается, например:
class ClumsyPlayer < Player do
def initialize(name, health = 100)
super(name, health)
@health_boost = rand(1..10)
end
end
Тогда в моей спецификации у меня возникла проблема с выяснением того, как заглушить неуклюжее случайное здоровье игрока, чтобы проверить, что, когда они получат исцеление, они получают правильный импульс к своему здоровью.
Трюк был:
@player.stub!(health_boost: 5)
Таким образом, что stub!
был ключом, я просто использовал stub
и все еще получал случайные пропуски rspec и отказы.
Так что спасибо Брайан
Ответ 3
mock
устарел на основе этого github pull.
Теперь вместо этого мы можем использовать double
- больше здесь...
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
Ответ 4
Current (3.x) RSpec предоставляет как чистые макетные объекты (как в tokhi answer), так и частичные издевательства (насмешливые звонки на существующий объект). Вот пример частичной насмешки. Он использует expect
и receive
, чтобы высмеять вызов Order
на CreditCardService
, так что тест проходит только в том случае, если вызов выполняется без фактического его выполнения.
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
В этом примере макет находится на возвращаемом значении CreditCardService.instance
, который предположительно является одиночным.
with
не является обязательным; без него любой вызов refund
удовлетворяет ожиданию. Возвращаемое значение может быть задано с помощью and_return
; в этом примере он не используется, поэтому вызов возвращает nil
.
В этом примере используется синхронный синтаксис RSpec current (expect .to receive
), который работает с любым объектом. В принятом ответе используется старый метод rspec-rails mock_model
, который был специфичен для моделей ActiveModel и был перемещен из rspec-rails на другой камень.