繁体   English   中英

使用和不使用Rails的快速(Rspec)测试

[英]Fast (Rspec) tests with and without Rails

我有两节课:

1.Sale是ActiveRecord的子类; 它的工作是将销售数据保存到数据库中。

class Sale < ActiveRecord::Base
  def self.total_for_duration(start_date, end_date)
    self.count(conditions: {date: start_date..end_date})
  end
  #...
end

2.SalesReport是一个标准的Ruby类; 它的工作是生成和绘制有关销售的信息。

class SalesReport
  def initialize(start_date, end_date)
    @start_date = start_date
    @end_date = end_date
  end

  def sales_in_duration
    Sale.total_for_duration(@start_date, @end_date)
  end
  #...
end

因为我想使用TDD并且我希望我的测试运行得非常快 ,所以我为SalesReport编写了一个不加载Rails的规范:

require_relative "../../app/models/sales_report.rb"

class Sale; end
# NOTE I have had to re-define Sale because I don't want to
# require `sale.rb` because it would then require ActiveRecord.

describe SalesReport do
  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

当我运行bundle exec rspec spec/models/report_spec.rb时,此测试有效

但是,当我运行bundle exec rake spec并且superclass mismatch for class Sale (TypeError)的错误superclass mismatch for class Sale (TypeError)时,此测试失败。 我知道错误正在发生,因为Tap是由sale.rb定义并在规范中内联。

所以我的问题是,如果没有定义该类,有一种方法可以将Stub(或Mock或Double)作为一个类吗? 这将允许我删除内联class Sale; end class Sale; end ,这感觉就像一个黑客。

如果没有,如何运行bundle exec rspecbundle exec rake spec ,我如何设置我的测试以使它们正确运行?

如果没有,我写快速测试的方法是错误的吗?!

最后,我不想使用Spork。 谢谢!

一种简单的方法是检查是否已定义“销售”

unless defined?(Sale)
  class Sale; end
end

在您的测试中,销售不一定是一个类,所以:

unless defined?(Sale)
  Sale = double('Sale')
end

RSpec最近添加的stub_const专门针对以下情况设计:

describe SalesReport do
  before { stub_const("Sale", Class.new) }

  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

您可能还想使用rspec-fire来代替Sale来使用测试双Sale来自动检查真实Sale类中存在的所有模拟/存根方法在运行带有真实Sale类的测试时(例如,当您运行测试时)套房):

require 'rspec/fire'

describe SalesReport do
  include RSpec::Fire

  describe "sales_in_duration" do
    it "calls Sale.total_for_duration" do
      fire_replaced_class_double("Sale")
      Sale.should_receive(:total_for_duration)
      SalesReport.new.sales_in_duration
    end
  end
end

如果在真正的Sale类上重命名total_for_duration ,则在模拟方法时rspec-fire会给出错误,因为它在实际类中不存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM