【问题标题】:When testing a method call that I know happens , I get a failure error stating the method was called 0 times在测试我知道发生的方法调用时,我收到一个失败错误,说明该方法被调用了 0 次
【发布时间】:2021-09-24 19:26:52
【问题描述】:

我有一个控制器,它在发出获取请求时调用 CSVCreator 类。 People 只是具有一些基本值(如姓名和头衔)的 Person 列表。

def index
    respond_to do |format|
      format.html
      format.csv { send_data CSVCreator.new(people).create }
end

我的 CSVCreator 看起来像这样

class CSVCreator 

  HEADERS = ["Name", "Date", "Title"].freeze

  def initialize(people)
      @people = people
  end

  def generate
      CSV.generate do |csv|
        csv << HEADERS
        @people.each do |person|
          row = [person.name, person.date, person.title] 
          csv << row
        end
      end
  end
end

我想知道如何在 Rspec 中进行测试?我试过的是

it "calls CSVCreator when get request is made" do
   csv_creator = double("CSVCreator")
   people = double("People")
   
   allow(csv_creator).to receive(:new).with(people)
   allow(csv_creator).to receive(:create)
   
   expect(csv_creator).to receive(:new).with(people)
   expect(csv_creator).to receive(:create)

   get :index, format: :csv
end

我的想法是将控制器与 CSVCreator 和 People 类解耦。所以为了测试控制器,我想看看它是否正确调用了它需要的方法,所以我为这些对象创建了测试替身。我是 RSpec 和一般测试的新手,所以如果我的方法不正确,请告诉我。

我的问题是,我说失败了

     Failure/Error: expect(csv_creator).to receive(:new).with(people)
 
   (Double "CSVCreator").new(#<Double "People">)
       expected: 1 time with arguments: (#<Double "People">)
       received: 0 times

我知道我的课程有效,它创建了 CSV,并且在控制器中调用了 CSVCreator.new(people).create。所以我很好奇为什么我会收到这个失败。

【问题讨论】:

    标签: ruby-on-rails ruby rspec


    【解决方案1】:

    在您的 CSVCreator 上创建一个类方法,该方法创建一个实例并调用 generate 方法:

    class CSVCreator 
      # ...
      def self.perform(people)
        new(people).generate
      end
    end
    
    def index
      respond_to do |format|
        format.html
        format.csv { send_data CSVCreator.perform(people) }
      end
    end
    

    这创建了一个更好的 API,因此消费者不必对类有太多的了解,并且更容易设定期望:

    it "calls CSVCreator when get request is made" do
       expect(CSVCreator).to receive(:perform)
       get :index, format: :csv
    end
    

    但是,people 中的存根问题更严重,这取决于它的实际实现方式。如果它是控制器上的一种方法,那么如果不使用 any_instance 就很难存根,这是一种代码味道。

    【讨论】:

      【解决方案2】:

      我猜输入参数 people 是在您的控制器中创建的,但我确定这不是您的双重“人”,您必须对 People 类的方法 :new 进行存根以返回 @987654323 @ of "People",或者如果你想确保 CSVCreator 是使用特殊的 "People" 创建的,例如在你的控制器中你调用它来获取人员:PeopleService.some_logic(..) -&gt; a_special_people,然后存根该方法 allow(PeopleService).to receive(:some_logic).and_return(instance_double_people)

      除此之外,您还可以创建 CSVCreator 的 instance_double,然后创建 CSVCreator 的存根方法 :new 以返回该 instance_double,现在您只需验证 instance_double 是否已调用 :create 方法,因为它确保CSVCreator 调用了:new,CSVCreator 的新实例调用了:create

      it "calls CSVCreator when get request is made" do
         csv_creator = instance_double(CSVCreator)
         people = instance_double(People)
      
         allow(People).to receive(:new).and_return(people)
         # allow(PeopleService).to receive(:some_logic).and_return(people)
         allow(CSVCreator).to receive(:new).with(people).and_return(csv_creator)
         allow(csv_creator).to receive(:create)
         
         get :index, format: :csv
         
         expect(csv_creator).to have_received(:create)
      end
      

      【讨论】:

        猜你喜欢
        • 2017-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多