我对模拟对象很陌生,正在尝试学习如何在RSpec中使用它们。请问是否可以提供一个示例(类似于“hello RSpec Mock object world”的示例),或者一个链接(或其他参考资料),介绍如何使用RSpec的模拟对象API?
我对模拟对象很陌生,正在尝试学习如何在RSpec中使用它们。请问是否可以提供一个示例(类似于“hello RSpec Mock object world”的示例),或者一个链接(或其他参考资料),介绍如何使用RSpec的模拟对象API?
这里是我为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
在这种情况下,我将Page和PageType模型(对象)进行了模拟,并存根化了我调用的一些方法。it "should be successful" do
Page.should_receive(:find_by_id).and_return(@page)
get 'show', :id => 1
response.should be_success
end
我知道这个答案更加关注Rails,但我希望它能在一定程度上帮到你。
编辑
好的,下面是一个"hello world"示例...
给出以下脚本(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
我没有足够的积分来评论回答,但我想说接受的答案也帮助我尝试找出如何存根随机值。
我需要能够存根对象的实例值,例如随机分配的值:
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通过和失败。
所以非常感谢Brian。
当您使用依赖项来“查询”某些内容时,您不需要使用“模拟API”,因为您可以使用普通对象,并在要测试的对象中测试预期输出...例如:
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
当你想要对依赖项进行更改或执行具有副作用的操作(如在数据库中插入新记录、发送电子邮件、进行付款等)时,现在你只需检查是否使用了正确的函数/方法和正确的属性,而不是测试更改或副作用是否已经发生...例如:
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
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
。
expect .to receive
)模拟语法,适用于任何对象。接受的答案使用了旧的rspec-rails mock_model
方法,它只适用于ActiveModel模型,并已被移出rspec-rails到另一个gem中。