我使用了一个装饰模块,它包含在模型实例中(通过“extends”方法)。例如:
module Decorator
def foo
end
end
class Model < ActiveRecord::Base
end
class ModelsController < ApplicationController
def bar
@model = Model.find(params[:id])
@model.extend(Decorator)
@model.foo
end
end
然后我想在测试中做以下事情(使用Mocha):
test "bar" do
Model.any_instance.expects(:foo).returns("bar")
get :bar
end
这有可能以某种方式,或者您是否有任何其他方式来获得此功能???
答案 0 :(得分:1)
它有效(在测试应用程序中使用render:text确认)
我通常包含装饰器(而不是在运行时扩展它们),我避免使用any_instance,因为它被认为是不好的做法(我试着改为查找)。
module Decorators
module Test
def foo
"foo"
end
end
end
class MoufesController < ApplicationController
def bar
@moufa = Moufa.first
@moufa.extend(Decorators::Test)
render :text => @moufa.foo
end
end
require 'test_helper'
class MoufesControllerTest < ActionController::TestCase
# Replace this with your real tests.
test "bar" do
m = Moufa.first
Moufa.expects(:find).returns(m)
m.expects(:foo).returns("foobar")
get :bar, {:id => 32}
assert_equal @response.body, "foobar"
end
end
答案 1 :(得分:1)
只是一个假设注意:我将假设您的装饰器foo 方法返回“bar”,这不会显示在您发送的代码中。如果我不假设这一点,那么期望会失败,因为该方法返回nil而不是“bar”。
假设如上所述,我已经尝试了整个故事,因为你有一个全新的rails应用程序,我已经意识到这是无法做到的。这是因为当您在测试中调用期望的方法时,方法'foo'不会附加到 Model 类。
我得出了这个结论,试图在期望时遵循所谓的方法堆栈。 期望 Mocha :: Central 中的调用存根,它在 Mocha :: ClassMethod中调用存根 ,在 Mocha :: AnyInstanceMethod 中调用* hide_original_method *。在那里,* hide_original_method *没有找到任何隐藏的方法,也没有做任何事情。然后 Model.foo 方法没有别名的存根mocha方法,应调用它来实现你的mocha期望,但实际的 Model.foo 方法被调用,您动态附加到控制器内的Model实例。
我的回答是无法做到这一点。
答案 2 :(得分:1)
好的,现在我明白了。您希望存根对外部服务的调用。有趣的是,摩卡不能用这种方式扩展。除了上面提到的,似乎是因为存根方法是在单例类而不是模块上定义的,所以不要混入。
为什么不是这样的?
test "bar" do
Decorator = Module.new{ def foo; 'foo'; end }
get :bar
end
如果你不想得到关于Decorator的警告已被定义 - 这暗示无论如何都会有一些耦合 - 你可以注入它:
class ModelsController < ApplicationController
class << self
attr_writer :decorator_class
def decorator_class; @decorator_class ||= Decorator; end
end
def bar
@model = Model.find(params[:id])
@model.extend(self.class.decorator_class)
@model.foo
end
end
使测试如下:
test "bar" do
dummy = Module.new{ def foo; 'foo'; end }
ModelsController.decorator_class = dummy
get :bar
end
当然,如果你有一个更复杂的情况,有多个装饰器或装饰器定义多个方法,这可能不适合你。
但我认为这比查找查找更好。您通常不希望在集成测试中存根模型。
答案 3 :(得分:0)
如果您想测试返回值:bar -
,则会有一个小的改动test "bar" do
Model.any_instance.expects(:foo).returns("bar")
assert_equal "bar", get(:bar)
end
但是如果你只是测试一个模型实例有装饰器方法,你真的需要测试吗?在这种情况下,您似乎正在测试Object #extend。
如果你想测试@ model.foo的行为,你不需要在集成测试中做到这一点 - 这是装饰器的优点,你可以单独测试它,如
x = Object.new.extend(Decorator)
#.... assert something about x.foo ...
根据我的经验,模拟集成测试通常是代码味道。