【问题标题】:Rspec how to test in inject methodRspec如何在注入方法中进行测试
【发布时间】:2016-02-22 05:41:14
【问题描述】:

我有一个看起来像这样的方法:

  def self.average_top_level_comments_leaders
    top_level_comment_count = CrucibleComment.group(:user_id).where(parent_comment_id: nil).order('count_all DESC').count
    code_review_assigned_count = Reviewer.group(:user_id).order('count_all DESC').count

    division_result = top_level_comment_count.inject({}) do |result, item|
      id = item.first #id =12
      count = item.last #value = 57
      if (count && code_review_assigned_count[id]) 
        result[id] = (count/ code_review_assigned_count[id]).round(2) 
        #result[12] = 57/12 = 3.3, => {12, 3.3}
      end
      result 
    end
  end

此方法返回一个哈希,其中 ID 作为键,除法的结果作为值。

我已成功测试了 top_level_comment_count 和 code_review_assigned 计数,但我无法弄清楚如何测试 do 块中的其他 4 项:

.first, .last, .round(2), result

我正在尝试测试 .first,这就是我目前所拥有的:

describe '#average_top_level_comments_leaders' do
    subject { User.average_top_level_comments_leaders}

    let(:avg_top_level_comments) { double }
    let(:code_review_count) { double }
    let(:item) { double( {id: 12}) }

    context 'when getting the comment count succeeds ' do
      before do
        allow(CrucibleComment).to receive(:group).with(:user_id).and_return(avg_top_level_comments)
        allow(avg_top_level_comments).to receive(:where).with(parent_comment_id: nil).and_return(avg_top_level_comments)
        allow(avg_top_level_comments).to receive(:order).with('count_all DESC').and_return(avg_top_level_comments)
        allow(avg_top_level_comments).to receive(:count).and_return(avg_top_level_comments)

        allow(avg_top_level_comments).to receive(:inject).and_return(avg_top_level_comments)
        allow(item).to receive(:first).and_return(item)

        allow(Reviewer).to receive(:group).with(:user_id).and_return(code_review_count)
        allow(code_review_count).to receive(:order).with('count_all DESC').and_return(code_review_count)
        allow(code_review_count).to receive(:count).and_return(code_review_count)
        allow(code_review_count).to receive(:round).with(2).and_return(code_review_count)
      end

      it 'and the correct parameters are called' do
        expect(CrucibleComment).to receive(:group).with(:user_id)
        subject
      end

      it 'and comment count is calling descending correctly' do
        expect(avg_top_level_comments).to receive(:order).with('count_all DESC')
        subject
      end

      it 'item gets the first result' do
        expect(item).to receive(:first)
        subject
      end
    end
  end

我无法让最后一个 it 语句通过。我试图期望(项目)。接收(:第一),但它在错误中说:

失败/错误:expect(item).to receive(:first) (双).first(*(任何参数)) 预期:1 次,带任何参数 收到:0 次,带任何参数

知道为什么这没有通过吗?另外两个它正在通过

【问题讨论】:

  • 恕我直言,您的测试耦合过于紧密。而不是所有的存根,设置数据,以便调用返回您知道它应该返回的内容并确保它确实如此。您不希望您的测试仅仅因为我将round 更改为等效的东西(即(... + 0.5).floor 或其他东西)而失败。
  • @PhilipHallstrom 现在我想起来了,我实际上只是想测试“结果”我该如何测试呢?

标签: ruby-on-rails rspec


【解决方案1】:

item double 从未在测试中使用,所以当它到达时:

expect(item).to receive(:first)

失败了。

如果您希望在此处的 inject 块中使用 item 双精度:

division_result = top_level_comment_count.inject({}) do |result, item|

仅仅由于它具有相同的名称,它就不能那样工作。您需要在 avg_top_level_comments double 上定义一个方法,该方法在调用 inject 时返回 item double。

但是,你不应该那样做。扔掉所有这些并使用真实的模型实例进行测试。它会更容易阅读和维护。

【讨论】:

  • 如何为这个测试做真实的模型实例?能举个例子吗?
  • 使用夹具或工厂在测试数据库中创建行,然后让作用域找到它们。这确实需要工作,而且速度会慢一些,但您会对最终结果更有信心。
  • 在这种情况下我无法使用数据库。一定是嘲讽。这可能吗?
  • 我犹豫地问,但是,为什么你不能使用数据库?至于是否可以全部模拟出来,是的,Ruby 一切皆有可能!但是,如果您不能使用测试数据库来测试您的应用程序,我会说这是房间里真正的大象。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多