stub方法与其他方法

时间:2013-11-12 09:53:03

标签: ruby-on-rails rspec

我的模特:

class Post < ActiveRecord::Base
 #...
 def my_method
   {:created_at => self.created_at, :words => self.text.split.find_by{/*my_conditiond_here*/}}
 end
 #...
end

控制器:

class TasksController < ApplicationController
 #...
 def my_action
   posts = Post.where(params[:conditions])
   @words = posts.map{|post| post.my_method}.flatten
 end
 #...
end

但是当我尝试对它进行测试时,我遇到了一些麻烦。

it "returns words for single post" do
  post = FactoryGirl.create :post, :text => 'any text here'
  get :my_action
  expect(assigns[:words]).to eq(post.my_method)
end

我得到类似的东西:

   expected: [{:words=>["any", "text", "here"], :created_at=>2013-11-12 09:33:04 UTC}]
        got: [{"words"=>["any", "text", "here"], "created_at"=>2013-11-12 09:33:04 UTC}]

不仅如此,如果我使用

  expect(assigns[:words].first).to eq(post.my_method.fitst.with_indifferent_access)

失败了:

   expected: {"words"=>["any", "text", "here"], "created_at"=>2013-11-12 09:33:04 UTC}
        got: {"words"=>["any", "text", "here"], "created_at"=>2013-11-12 09:33:04 UTC}
   (compared using ==)

   Diff:

通过实验,我在created_at元素中意识到了这个问题。

看起来可能存根my_method但我不知道如何返回连接到对象的值。比如id。 或建议请更好地测试my_action

1 个答案:

答案 0 :(得分:0)

我会做以下其中一项,但优先考虑第二种解决方案(消息预期):

  1. 仅检查words数组,而不检查created_at等时间戳。
  2. 将所有Post::where#map调用封装到Post上的描述性类/单例方法中,并检查Post是否收到了正确的消息。这样,您只检查正确的消息是否传递给Post,而不是测试Post和控制器。
  3. 换句话说,对于上面的解决方案#2,您可能会这样:

    <强> post.rb:

    class Post
      def self.posts_with_my_method params
        # move code from controller here
      end
    end
    

    <强> tasks_controller.rb:

    class TasksController < ApplicationController
     #...
      def my_action
        @words = Post.posts_with_my_method params(params)
      end
      #...
     end
    

    <强>规格:

    it "returns words for single post" do
      Post.should_receive(:posts_with_my_method).and_return([:foo])
      get :my_action
      expect(assigns[:words]).to eq([:foo])
    end