Rspec对象比较失败(Ruby on Rails)



我写了一个简单的规范来测试更新操作无效属性。我希望obj属性保持不变,但是由于一些奇怪的原因,测试失败了,尽管属性仍然是相同的。

谢谢你的建议。

规范

require 'rails_helper'
RSpec.describe Api::V1::PatientsController, type: :controller  do
    # ...
    ## 1.2
    # Update patient
    describe "PUT #update patient" do
      let(:patient_attributes) { attributes_for(:patient_for_contact) }
      # Useful variables
      let(:patient_id) { patient_attributes[:patient_id] }
      let(:physio_center_code) { patient_attributes[:physio_center_code] }
      let(:physio_center_id) { PhysioCenter.find_by_code(physio_center_code).id }
      # let! force the method's invocation before each example (not lazy evaluated).
      let!(:patient) { create(:patient, patient_id: patient_id, physio_center_id: physio_center_id) }

      context "with wrong attributes" do
        # invalid attributes with the same :patient_id, :physio_center_code
        let(:invalid_patient_attributes) { attributes_for(:invalid_patient_for_contact, patient_id: patient_id, physio_center_code: physio_center_code) }
        # IT PASSES
        it "respond with 422" do
          put :update, patient: invalid_patient_attributes
          expect(response.status).to eq(422)
        end
        # IT FAILS
        it "doesn't change the attributes of the patient (TO FIX)" do
          put :update, patient: invalid_patient_attributes
          # set variables
          not_updated_patient = Patient.where(patient_id: patient_id, physio_center_id:  physio_center_id).take
          expect(not_updated_patient.attributes).to eq(patient.attributes) #--> FAIL
          # expect(not_updated_patient).to have_attributes(patient.attributes) #--> FAIL
        end
      end
    end
  end
end
h2控制器

module Api
  module V1
    class PatientsController < ApplicationController
      before_action :set_physio_center, only: [:create, :update]
      before_action :set_patient, only: :update
      def update
        if @patient
          patient_params.extract!(:patient_id, :physio_center_code)
          if @patient.update_attributes(patient_params)
            render json: {message: "Patient updated"}, status: 204
          else
            render json: @patient.errors, status: :unprocessable_entity
          end
        end
      end
      protected
      def set_physio_center
        physio_center_code = params[:patient][:physio_center_code]
        # find_by() doesn't raise exception if record_not_found, so i force it if nil
        @physio_center = PhysioCenter.find_by_code(physio_center_code) ||
            raise(ActiveRecord::RecordNotFound, message: "Couldn't find PhysioCenter with 'physio_center_code'=#{physio_center_code}.n")
      end
      def set_patient
        patient_id = params[:patient][:patient_id]
        @patient = Patient.find_by(patient_id: patient_id, physio_center_id: @physio_center.id) ||
            raise(ActiveRecord::RecordNotFound, message: "Couldn't find Patient with 'patient_id'=#{patient_id} and 'physio_center_id'=#{@physio_center.id}.n")
      end
    end
  end
end
工厂

FactoryGirl.define do
  factory :patient_for_contact do
    sequence (:patient_id) { |n| (121+n) }
    birth_date { FFaker::Time.date }
    gender { ["M","F"].sample }
    weight { rand(15.0...120.9).round(1) }
    height { rand(80...220).round(0) }
    bmi { rand(15.0...120.9).round(1) }
    injury_id { Injury.all.ids.sample } # gestisco manualmente
    physio_center_code { (PhysioCenter.all.empty?)? create(:physio_center).code : PhysioCenter.first.code } # Il PhysioCenter non viene creato!
  end
  factory :invalid_patient_for_contact, parent: :patient_for_contact do |f|
    f.gender nil
    f.injury_id nil
  end
end
结果


1) Api::V1::PatientsController with right email and authentication_token PUT #update patient with wrong attributes doesn't change the attributes of the patient
     Failure/Error: expect(not_updated_patient.attributes).to eq(patient.attributes) #--> FAIL
       expected: {"id"=>2, "patient_id"=>123, "physio_center_id"=>2, "birth_date"=>Sun, 09 Jan 2011, "gender"=>"F", "weight"=>25.3, "height"=>105, "bmi"=>22.9, "injury_id"=>8, "created_at"=>Sat, 22 Aug 2015 13:03:29 UTC +00:00, "updated_at"=>Sat, 22 Aug 2015 13:03:29 UTC +00:00}
            got: {"id"=>2, "patient_id"=>123, "physio_center_id"=>2, "birth_date"=>Sun, 09 Jan 2011, "gender"=>"F", "weight"=>25.3, "height"=>105, "bmi"=>22.9, "injury_id"=>8, "created_at"=>Sat, 22 Aug 2015 13:03:30 UTC +00:00, "updated_at"=>Sat, 22 Aug 2015 13:03:30 UTC +00:00}
       (compared using ==)
       Diff:
       @@ -1,6 +1,6 @@
        "bmi" => 22.9,
       -"created_at" => Sat, 22 Aug 2015 13:03:29 UTC +00:00,
       +"created_at" => Sat, 22 Aug 2015 13:03:30 UTC +00:00,
        "gender" => "F",
       @@ -9,6 +9,6 @@
        "physio_center_id" => 2,
       -"updated_at" => Sat, 22 Aug 2015 13:03:29 UTC +00:00,
       +"updated_at" => Sat, 22 Aug 2015 13:03:30 UTC +00:00,
        "weight" => 25.3,

注意:有时Diff为空。

似乎在created_atupdated_at的比较中存在一些错误。我不明白为什么会有不同的价值观。我从DB中选择相同的资源…

我也试过

expect(not_updated_patient).to have_attributes(patient.attributes)

但是它也失败了。

我的开发环境:

    Ruby 2.2.0
  • Rails 4.2.0
  • FactoryGirl (4.5.0)
  • rspec (3.2.0)
  • rspec-core (3.2.3)
  • rspec-expectations (3.2.1)
  • rspec-rails (3.2.1)
  • DatabaseCleaner (1.4.1)
  • mysql2 (0.3.18)
  • 春(1.3.6)
  • spring-commands-rspec (1.0.4)

它们是不一样的,你应该选择一个设置的属性来比较。updated_atcreated_at不同

也许

?

expect(not_updated_patient.attributes.without('updated_at', 'created_at')).to eq(patient.attributes.without('updated_at', 'created_at'))

使用这个帮助

class Hash
  def without(*keys)
    cpy = self.dup
    keys.each { |key| cpy.delete(key) }
    cpy
  end
end

最新更新