【问题标题】:How to fix RSpec test that depends on time passing by如何修复取决于时间流逝的 RSpec 测试
【发布时间】:2021-01-21 19:29:11
【问题描述】:

我的一个控制器中有以下方法:

def ping
  @obj.last_ping_at = DateTime.now
  @obj.save!
end

我想测试它是否有效,所以我编写了以下测试:

it 'successfully updates last_ping_at' do
  old_last_ping_at = obj.last_ping_at
  patch url(obj)
  expect(response).to have_http_status(:ok)
  expect(obj.reload.last_ping_at).not_to eql(old_last_ping_at)
end

问题是:时间总是一样的。改变它的唯一方法是,如果我将 binding.pry 添加到控制器方法然后继续。

【问题讨论】:

  • this 讨论对您有帮助吗?

标签: ruby-on-rails rspec


【解决方案1】:

last_ping_at 设置为绝对不是现在的值,然后使用be_within 检查它是否接近现在。

it 'successfully updates last_ping_at' do
  obj.update!(last_ping_at: 1.day.ago)

  patch url(obj)

  expect(response).to have_http_status(:ok)
  expect(obj.reload.last_ping_at).to be_within(1.second).of(DateTime.now)
end

注意:DateTime.now 将是您机器上的时区,而不是应用程序的时区。请改用DateTime.current

[4] pry(main)> Time.zone = "Fiji"
=> "Fiji"
[5] pry(main)> DateTime.now
=> Thu, 21 Jan 2021 12:13:14 -0800
[6] pry(main)> DateTime.current
=> Fri, 22 Jan 2021 08:13:16 +1200
[7] pry(main)> 

It's About Time (Zones)


有时您不能使用be_within。在这种情况下,您可以冻结时间。对于一般 Ruby use timecop as @max says。 Rails 内置了 travel_to

it 'successfully updates last_ping_at' do
  travel_to Time.current do
    patch url(obj)

    expect(response).to have_http_status(:ok)
    expect(obj.reload.last_ping_at).to eq Time.current
  end
end

我更进一步,将其烘焙到 rspec 元数据中。

# spec/support/config/travel_to.rb
RSpec.configure do |config|
  config.around do |example|
    if example.metadata[:travel_to]
      travel_to example.metadata[:travel_to] do
        example.run
      end
    else
      example.run
    end
  end
end

现在您可以在任何 RSpec 块中travel_to: Time.current

it 'successfully updates last_ping_at', travel_to: Time.current do
  patch url(obj)

  expect(response).to have_http_status(:ok)
  expect(obj.reload.last_ping_at).to eq Time.current
end

YMMV,无论您更喜欢显式块还是隐式元数据。

【讨论】:

    【解决方案2】:

    你可以使用travel方法:

    it 'successfully updates last_ping_at' do
      old_last_ping_at = obj.last_ping_at
    
      travel 1.day do
        patch url(obj)
        expect(response).to have_http_status(:ok)
        expect(obj.reload.last_ping_at).not_to eql(old_last_ping_at)
      end
    end
    

    https://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html#method-i-travel

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      相关资源
      最近更新 更多