2

我正在使用timecop gem 来删除日期。我还在使用factory_girl以便更轻松地为我的规格创建对象。

这是我的工厂:

FactoryGirl.define do
  factory :fiscal_year do
    start_date  {Date.today}
    end_date    {Date.today + 1.day}

    trait(:sequenced_start_date) {sequence(:start_date, Date.today.year)  {|n| Date.new(n, 10, 1) }}
    trait(:sequenced_end_date)   {sequence(:end_date,   Date.today.year + 1)  {|n| Date.new(n, 9, 30) }}


    factory :sequenced_fiscal_year, parent: :fiscal_year,
            traits: [:sequenced_start_date, :sequenced_end_date]
  end
end

假设今天的实际日期是 09/07/2016。

这是我的规格:

RSpec.describe FiscalYear, type: :model do
  before(:example) do
    Timecop.freeze(Time.local(2010))
  end
  after do
    Timecop.return
  end

  describe "fake spec to show unexpected sequence behavior" do
    it "tests something" do
      puts "Today's frozen date thanks to Timecop: #{Date.today}"
      fiscal_year = create(:sequenced_fiscal_year)
      puts "Sequenced Date: #{fiscal_year.end_date}"
    end
  end
end

当规范在这里运行时是输出:

Today's frozen date thanks to Timecop: 01/01/2010
Sequenced Date: 09/30/2017

在第一行输出中: Timecop 在我调用时按预期工作Date.today。它已成功冻结时间并返回该冻结时间。

但是:第二行没有按预期工作。它显然是在使用该系统Date,而不是 Timecop 的 frozen Date。排序的end_date应按顺序将 +1 年添加到当前冻结的日期。因此:我希望end_date这里是09/30/2011,而不是09/30/2017

我怎样才能使序列end_date化的属性脱离 Timecop 的Date而不是系统的Date

4

1 回答 1

2

问题在于我传递给该sequence方法的第二个参数。该参数在初始化时是静态的/评估的。它不是动态的,因此timecop在评估第二个参数之前没有机会存根日期。

trait(:sequenced_end_date) {sequence(:end_date, Date.today.year + 1)  {|n| Date.new(n, 9, 30) }}

传递给方法的第二个参数的那Date.today.year部分sequence是静态的,并在初始化时进行评估。它不是动态的,甚至在调用该方法之前就已经对其进行了评估。

我只需要将这些方法更改为以下内容:

trait(:sequenced_year_start_date) {sequence(:start_date)  {|n| Date.new(Date.today.year, 10, 1) }}
trait(:sequenced_year_end_date)   {sequence(:end_date)    {|n| Date.new(Date.today.year + n, 9, 30) }}

现在它按预期工作并返回以下内容:

Today's frozen date thanks to Timecop: 01/01/2010
Sequenced Date: 09/30/2011

块是动态的,因此Date.today.year + n在块内调用使 timecop 有机会Date在执行此块之前首先存根。

于 2016-09-07T16:41:13.660 回答