這就是爲什麼我不像ActiveRecord回調 - 因爲如果你想與回調沒有關係(因爲你打電話給回調中的外部服務),你仍然需要關心它的存在。是的,你可以在回調中刪除方法,但它是同樣的問題,實際上它有點更糟,因爲現在你關心的是裏面的,這是一種你不想要的方法。
像往常一樣,這裏有多個選項。
過去我曾經使用過的一個選項是,在你的回調中添加一個條件,默認關閉它。因此,郵政類可能看起來像:
class Post
before_save :sync_with_store, :if => :syncing_with_store?
def syncing_with_store?; @syncing_with_store; end
attr_writer :syncing_with_store
def sync_with_store
# make an HTTP request or something
end
end
現在只要你真的想調用回調(也許在您的控制器或其它地方),你可以設置post.syncing_with_store = true
你打電話之前post.save
。
這種方法的缺點是,你(和其他開發人員一起工作)必須牢記在心,而且你不得不這麼做。另一方面,如果你忘記這麼做,沒有什麼不好的事情發生。
另一種選擇是使用假類。假設你有一個Post,在保存時將其數據推送到外部數據存儲。您可以提取推送到單獨的類(例如Pusher)的代碼,該代碼可以在Post.pusher_service
訪問。但是,默認情況下,這將被設置爲一個假的Pusher類,它響應相同的接口但什麼也不做。所以像:
class Post
class << self
attr_accessor :pusher_service
end
self.pusher_service = FakePostPusher
before_save :sync_with_store
def sync_with_store
self.class.pusher_service.run(self)
end
end
class FakePostPusher
def self.run(post)
new(post).run
end
def initialize(post)
@post = post
end
def run
# do nothing
end
end
class PostPusher < FakePostPusher
def run
# actually make the HTTP request or whatever
end
end
在您的生產環境文件中,您將設置Post.pusher_service = Pusher
。在個別測試或測試案例中,您將創建Post - let(:klass) { Class.new(Post) }
的子類 - 並設置klass.pusher_service = Pusher
(這樣您不會永久設置它並影響將來的測試)。
我一直在嘗試的第三種方法是:簡單地不要使用ActiveRecord回調。這是我從Gary Bernhardt's screencasts(其中,順便說一句,相當驚人)拿起的東西。相反,定義一個包裝創建帖子行爲的服務類。喜歡的東西:
class PostCreator
def self.run(attrs={})
new(attrs).run
end
def initialize(attrs={})
@post = Post.new(attrs)
end
def run
if @post.save
make_http_request
return true
else
return false
end
end
def make_http_request
# ...
end
end
這樣PostCreator.run(attrs)
是創建一個職位,而不是通過後會事實上的方式。現在要在Post中測試保存,不需要存儲回調。如果你想測試PostCreator過程,沒有魔法發生,你可以很容易地找出你想要的任何方法或獨立測試它們。 (你可以爭辯說,這裏提到的方法與截取AR回調相同,但是我認爲它更明確地發生了什麼。)顯然這隻能處理後期創建,但對於後期更新也可以做同樣的事情。
無論如何,不同的想法,挑選你的毒藥。
但是,我將不得不做'Fabricate.build',然後存根和保存,而不是隻是創建。 – RocketR 2012-05-15 18:03:55
好的,那麼你想在這裏測試什麼?在這種情況下,測試與#set_some_values無關,所以您只需創建一個用戶並將#set_some_values的副作用存根刪除? – 2012-05-16 16:54:28
是的。我並不在乎這個方法本身,只需要把它拿下來。 _P.S._好吧,現在我想我可以只存留'set_some_values'所使用的對象。 – RocketR 2012-05-16 20:04:13