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

时间:2015-08-22 13:54:56

标签: ruby-on-rails ruby ruby-on-rails-4 rspec

我编写了一个简单的规范,用无效属性测试更新操作。我希望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

控制器

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)
  • spring(1.3.6)
  • spring-commands-rspec(1.0.4)

1 个答案:

答案 0 :(得分:0)

它们与您应该选择要比较的抵消属性不同。 updated_atcreated_at不同。

也许?

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

使用此helper

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