将服务类与Rails环境分离

时间:2012-12-07 10:50:52

标签: ruby-on-rails ruby decoupling

假设我的rails应用程序中有一个服务类。它的作用并不重要,但我们假设它可以用于向客户推送通知。

# lib/services/event_pusher.rb
class EventPusher
  def initialize(client)
    @client = client
  end

  def publish(event)
    PusherGem.trigger(@client, event)
  end
end

我现在可以在我的控制器中使用这个类:

require "lib/services/event_pusher"

class WhateverController < ApplicationController
  def create
    @whatever = Whatever.new(params[:whatever])

    if @whatever.save
      EventPusher.new(current_user).publish('whatever:saved')
    end
  end
end

现在,当我致电publish时,此服务类会向第三方发出请求。我在运行测试时不希望这种情况发生。

我看到它的方式我有两种选择。

选项1:
我必须记住使用环境检查将所有对EventPusher.trigger的调用后缀。请记住,我可以在我的应用程序中的每个创建/更新/销毁操作中调用它。

if @whatever.save
  EventPusher.new(current_user).publish('whatever:saved') unless Rails.env.test?
end

选项2:
我必须将我的服务类耦合到Rails。

def publish(event)
  PusherGem.trigger(@client, event) unless Rails.env.test?
end

哪个是正确的选项(或者是否有一个秘密选项3)?

1 个答案:

答案 0 :(得分:1)

您使用的是RSpec吗?如果是这样,您可以在测试本身内覆盖EventPusher的发布方法的功能,如下所示:

EventPusher.any_instance.stub(:publish)

上面的代码用一个返回nil的空方法替换了原始的publish方法。该方法仍然存在,仍将被调用,但它不会在您的测试范围内做任何事情。

如果其他代码期望发布方法返回某些内容,例如“true”以表示成功,那么您可以添加以下内容:

EventPusher.any_instance.stub(:publish).and_return(true)

或者,如果你更喜欢覆盖PusherGem的静态触发器方法,那么使用这种稍微不同的语法:

PusherGem.stub!(:trigger)

PusherGem.stub!(:trigger).and_return("something here, perhaps?")