Ruby 困惑于如何使用模拟和存根
我有一个等级和一个规格Ruby 困惑于如何使用模拟和存根,ruby,rspec,Ruby,Rspec,我有一个等级和一个规格 class Store def activate(product_klass, product_id) product = product_klass.find(product_id) if product.inactive? product.update_attribute :active, true end end end describe Store do it "should activate an inactiv
class Store
def activate(product_klass, product_id)
product = product_klass.find(product_id)
if product.inactive?
product.update_attribute :active, true
end
end
end
describe Store do
it "should activate an inactive product" do
product = mock
product.stub(:inactive?).and_return(true)
store = Store.new
store.activate(22) #
product.should be_active
end
end
运行规范失败。我得到:
Mock received unexpected message :find_by_id with (1)
为了满足这一点,我在行store.activate(产品,22)
之前添加了product.should.\u receive(:find\u by\u id.).with(1.)和
。(这样做似乎是错误的,因为我不希望我的测试对我正在测试的方法的内部了解太多)
再次运行规范,我得到失败,以下行返回false
,而不是预期的true
:
product.should be_active
因此,它返回false
,因为product.update\u属性:active,true
并没有真正将active
设置为true
:它只是被模拟吸收了
我有很多问题。一个人是如何进行选择的?我应该如何测试这个呢?我是否正确使用模拟和存根
非常感谢您的帮助。我认为激活逻辑根本不属于
存储
。如果它是在产品中声明的
,那么测试对我来说会自然得多:
class Product < ActiveRecord::Base
def activate
if inactive?
update_attribute :active, true
end
end
end
describe Product do
it "should activate an inactive product" do
product = Product.new
product.activate
product.should be_active
end
end
我同意@padde的观点,即产品激活应该在
产品
模型上,因此:
class Product < ActiveRecord::Base
def activate
if inactive?
update_attribute :active, true
end
end
end
以及存储
测试:
describe Store do
context "when activating a product" do
let(:product) { mock }
let(:store) { Store.new }
before do
product_klass = double # Stub the product class, don't mock
product_klass.stub(:find) { product } # We want to test product here, not the class
store.activate(product_klass, 22)
end
subject { product } # product is the subject again
it { should_receive(:activate) } # it should receive the activate message
end
end
我删除了对产品的期望,因为在本例中,这并不是您真正感兴趣的测试内容。你可能会喜欢把它作为一个单独的测试
使用let
,subject
和context
以标准方式安排您的测试,并允许rspec做一些整洁的事情,如生成类的人性化文档。有关rspec最佳实践的更多信息,请参阅。好的,我了解要点。但是我不喜欢这样的想法,我必须在那里有一行product\u klass.should\u receive(:find).和
。这似乎太过分了,使规范变得脆弱?。如果我要更改产品的获取方式,那么我也必须更改规范。对于方法的逻辑来说,记录的获取方式非常重要,不是吗?也许您可以将其提取到一个单独的方法中,该方法根据记录的类型(类)获取记录并保持Store.activate
simpler。如果您甚至需要在存储
中使用方法激活
,或者您可以直接在产品
上调用该方法,请先检查。
describe Product do
context "after activating" do # Human readable situation of the test
let(:product) { Product.new.activate }
subject { product } # Make product the subject of the test
it { should be_active } # Product should be active
end
end
describe Store do
context "when activating a product" do
let(:product) { mock }
let(:store) { Store.new }
before do
product_klass = double # Stub the product class, don't mock
product_klass.stub(:find) { product } # We want to test product here, not the class
store.activate(product_klass, 22)
end
subject { product } # product is the subject again
it { should_receive(:activate) } # it should receive the activate message
end
end