3 votes

RSpec et Factory Girl - Erreur avec le champ datetime

Je suis confronté au problème suivant :

Environnement : Ruby: 2.3.1 et Rails 5.0.0.1

J'essaie de valider un champ datetime avec RSpec et Factory Girl.

J'ai obtenu cette erreur :

attendu : "2016-11-11 13:30:31 UTC"  (De Factory Girl)
     obtenu : "2016-11-11T13:30:31.218Z" (De la base de données)

Mon code :

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

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

  it "renvoie une liste de #{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
  ...

Factory :

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

fin

Comment puis-je corriger ce problème ?

J'ai fait cela, ça fonctionne mais je pense que ce n'est pas la meilleure façon de le faire. Y a-t-il une meilleure façon de le faire ?

    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

Merci pour votre aide.

2voto

evgeniy_trebin Points 695

Je peux vous suggérer de changer votre approche pour comparer les résultats. Vous pouvez utiliser une approche basée sur l'idée du maître doré.

En suivant cette approche, vous prenez un instantané d'un objet, puis comparez toutes les versions futures de l'objet à l'instantané.

Dans votre cas, vous pouvez écrire une fixture json la première fois, vérifier que le json est correct et le comparer avec le json résultant la prochaine fois.

Par exemple

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": "Moscou",
    "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
  ...

Approvals gem, par exemple, peut vous aider avec cela

1voto

Kate Donaldson Points 46

Je sais que cette question est très ancienne mais je viens de trouver la solution aujourd'hui et je n'ai pas pu trouver une autre réponse. J'ai aussi utilisé Faker, mais les formats de Date/Heure ne semblent pas fonctionner très bien avec les calculs de temps Ruby sans beaucoup de manipulations.

Cependant, si vous utilisez Time dans votre factory, puis le convertissez en .to_i, cela sera envoyé à la db dans le bon format pour la comparaison dans rspec.

Migration:

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

Factory:

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

Spec:

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

Ensuite, mes tests ont réussi. J'espère que cela aidera quelqu'un d'autre !

0voto

Michael Malov Points 1409

Essayez d'utiliser to_datetime au lieu de to_s

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X