RSpec和Factory Girl - datetime字段出错

时间:2016-11-11 14:41:54

标签: ruby-on-rails ruby rspec

我遇到以下问题:

环境:Ruby:2.3.1和Rails 5.0.0.1

我正在尝试使用RSpec和Factory Girl验证日期时间字段。

我收到了这个错误:

expected: "2016-11-11 13:30:31 UTC"  (From Factory Girl)
     got: "2016-11-11T13:30:31.218Z" (From database)

我的代码:

klass_object = FactoryGirl.create(:character)
klass = Character


RSpec.shared_examples 'API GET #index' do |klass|
  before { get :index, params: params, accept: Mime[:json] }


  it "returns a list of #{klass.to_s.underscore.pluralize}" do
    object_array = json(response.body)

    klass_attributes = klass.attribute_names.without("id", "created_at", "updated_at").map(&:to_sym)

    klass_attributes.each do |attribute|
      object_array.each do |object|
        expect(object[attribute].to_s).to eq(klass_object[attribute].to_s)
      end
    end
  end
  ...
end

厂:

FactoryGirl.define do
  factory :character do
    marvel_id { Faker::Number.number(6).to_i }
    name { Faker::Superhero.name }
    description { Faker::Hipster.paragraphs(1) }
    modified { Faker::Date.between(DateTime.now - 1, DateTime.now) }

    factory :invalid_character do
      id ''
      name ''
      marvel_id ''
      modified ''
    end
  end

如何更正此问题?

我做到了,它有效,但我认为它不太好。还有更好的方法吗?

    object_array.each do |object|
      if ActiveSupport::TimeWithZone == klass_object[attribute].class
        expect(object[attribute].to_datetime.strftime("%Y-%m-%d %H:%M:%S")).to eq(klass_object[attribute].to_datetime.strftime("%Y-%m-%d %H:%M:%S"))
      else
        expect(object[attribute].to_s).to eq(klass_object[attribute].to_s)
      end
    end

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

我建议你改变比较结果的方法。您可以使用基于黄金大师的想法的方法。

根据此方法,您可以拍摄对象的快照,然后将对象的所有未来版本与快照进行比较。

在你的情况下,你可以第一次写json fixture,检查json是否正确,并在下次将它与结果json进行比较。

例如

<强> approved.json

[
  {
    "travel_time_seconds": 43200,
    "available_seats_amount": 10,
    "departure_at": "2016-04-08T02:00:00.000+03:00",
    "arrival_at": "2016-04-08T17:00:00.000+03:00",
    "source_point_name": "New York",
    "destination_point_name": "Moscow",
    "tickets_count": 2
  }
]

<强> controller_spec.rb

RSpec.shared_examples 'API GET #index' do |klass|
  before { get :index, params: params, accept: Mime[:json] }

  it "returns a list of #{klass.to_s.underscore.pluralize}" do
    verify(format: :json) { json(response.body).map {|o| o.except('id', 'created_at', 'updated_at' }
  end
  ...
end
例如,

approvals gem可以为您提供帮助

答案 1 :(得分:1)

我知道这是一个非常古老的问题,但我今天刚刚遇到了这个问题的解决方案而无法找到另一个答案。我也一直在使用Faker,但是日期/时间格式在Ruby时间数学上似乎没有很好的效果,而且没有大量的探索。

但是,如果您在工厂中使用Time,然后将其转换为.to_i,它将以正确的格式发送到数据库,以便在rspec中进行比较。

迁移:

class CreateExperiences < ActiveRecord::Migration[5.2]
  def change
    create_table :experiences do |t|
      t.datetime :start_date

厂:

FactoryBot.define do
  when_it_started = Time.zone.now - rand(3000).days
  factory :experience do
    start_date { when_it_started.to_i }

规格:

RSpec.describe "Experiences API", type: :request do
  let!(:valid_attributes) { attributes_for(:experience) }
  describe "POST /v1/experiences" do
    before { post "/v1/experiences", params: valid_attributes }
      it "creates an experience" do
        expect(JSON.parse(response.body).except("id", "created_at", "updated_at")).to eq(valid_attributes.stringify_keys)
      end

然后我的测试通过了。希望这会帮助别人!

答案 2 :(得分:0)

尝试使用to_datetime代替to_s

expect(object[attribute].to_datetime).to eq(klass_object[attribute].to_datetime)