【问题标题】:how can I test scope with rspec如何使用 rspec 测试范围
【发布时间】:2013-04-16 21:47:34
【问题描述】:

这些是我的 Cashout 模型的一些代码。我可以使用 rspec 测试所有模型,但我不知道如何测试这些范围。

cashout.rb

class Cashout < ActiveRecord::Base

belongs_to :partner

scope :add_virtual_columns, select(
    "cashouts.*,
    ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id) as total_paid_amount,
    (
      (
      CASE
        WHEN (SELECT partner_type FROM partners WHERE cashouts.partner_id = partners.id) = 'administrator'
        THEN
          (
            CASE 
                WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id))) IS NULL
                THEN 0 
                ELSE ( SELECT SUM(cr.partner_profit + cr.company_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id)))
            END
            )
        ELSE
          (
          CASE 
            WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id) IS NULL
            THEN 0 
            ELSE ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id)
          END
          )
      END
      )
      -
      ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id)
    ) as unpaid_amount"
  ).group('cashouts.id')
  scope :sort_by_total_paid_amount_asc, order("total_paid_amount ASC")
  scope :sort_by_total_paid_amount_desc, order("total_paid_amount DESC")
  scope :sort_by_unpaid_amount_asc, order("unpaid_amount ASC")
  scope :sort_by_unpaid_amount_desc, order("unpaid_amount DESC")
end

您知道如何使用 rspec 和 factorygirl 测试这些范围吗?

【问题讨论】:

    标签: ruby-on-rails rspec scope


    【解决方案1】:

    大致猜测您的架构,您首先必须为所有部分及其关联设置工厂。这是一个粗略的轮廓。您必须使用有效值填写它们的其他属性。

    Faker对于填写有效数据非常有用。

    factory :company do
    end
    
    factory :partner do
      company
    end
    
    factory :contact_record do
      partner
    end
    
    factory :cashout do
      partner
      total_paid_amount { Faker::Number.digit }
    end
    

    测试排序范围很容易。制作一组不同金额的兑现,按照您的预期对它们进行排序,然后看看您是否能取回。

    我们的工厂已经准备好以随机的 total_paid_amounts 给我们现金。我们只需要创建一个它们的列表。

    context 'with cashouts' do
      let(:cashouts) {
        create_list(:cashout, 3)
      }
    
      describe '.sort_by_total_paid_amount_asc' do
        it 'sorts by total_paid_amount in ascending order' do
          expect(
            Cashout.sort_by_total_paid_amount_asc.to_a
          ).to eq cashouts.sort_by(&:total_amount_paid)
        end
      end
    
      describe '.sort_by_total_paid_amount_desc' do
        it 'sorts by total_paid_amount in descending order' do
          expect(
            Cashout.sort_by_total_paid_amount_desc.to_a
          ).to eq cashouts.sort_by(&:total_amount_paid).reverse
        end
      end
    end
    

    我避免按顺序生成提款。这会将它们按顺序排列在表格中,并且它们的默认排序可能符合我们的预期。

    虽然我质疑这种字面意思和微不足道的作用域的价值。它们很容易写成Cashout.order(total_paid_amount: :asc),不需要测试。


    测试add_virtual_columns...add_virtual_columns 是一个糟糕的名字。似乎它正在添加一个列,unpaid_amount。我会称之为with_unpaid_amount

    with_unpaid_amount 更复杂,因为它非常复杂并且需要更多的测试数据。幸运的是,我们在工厂中建立了关系。

    首先,我们将对象设置为共享同一个伙伴。有几种方法可以做到这一点,但我选择生成伙伴并传递它。这样可以更轻松地修改每个对象以测试不同的场景。

    describe '.with_unpaid_amount' do
      let(:partner) {
        create(:partner)
      }
      let(:company) {
        create(:company, partner: partner)
      }
      let(:cashout) {
        create(:cashout, partner: partner)
      }
      let(:contact_record) {
        create(:contact_record, partner: partner)
      }
    

    有了这个,您现在可以更改对象以测试不同的场景。例如,如果合作伙伴是管理员怎么办?

      context 'when the partner is an administrator' do
        before {
          partner.update!(partner_type: 'administrator')
        }
    
        it '...'    
      end
    

    从那里开始等等。

    【讨论】:

      【解决方案2】:

      我倾向于创建一些测试数据并将示波器结果与您期望的结果进行比较。 FactoryGirl 可以帮助您创建基础Cashout 模型,您可以在其上覆盖amountpartner_id,然后生成对应的PartnerContactRecord 模型。

      对于后面的范围,您可以执行类似的操作

      Cashout.sort_by_total_paid_amount_asc.to_sql.should == \ 
      Cashout.order('total_paid_amount ASC').to_sql
      

      【讨论】:

      • 我投了反对票。测试原始 SQL 是对范围的具体实现进行玻璃盒测试;如果实现稍有改变,测试就会中断,因为根本无法将这样一个简单的查询放在一个范围内。更糟糕的是,它不会检查范围是否完成了它的工作:排序。
      猜你喜欢
      • 1970-01-01
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      • 1970-01-01
      相关资源
      最近更新 更多