Rspec and Rails 4, update skip callback

2019-01-15 17:33发布

问题:

I try to run an update test with rspec for my rails application.

I'm using rspec 3.5 and rails 4.

The behaviour is supposed to be the following :

When i create a new service with a selling price, it's create a Price instance and set the relation with the service. Then, when i update my service, if there is no selling price, it's destroy the price record (requirement of the client to save space in database). The process i implemented seems to be working fine, when i test with the UI and i check the count of Price record, it's decrease by one like it's suppose. However, the unit test if failing.

Here is the code :

Service Controller :

  def update
    @service.assign_attributes(service_params)

    puts "update method"

    respond_to do |format|
      if @service.valid?
        if params['preview']
          @service.build_previews
          format.js { render 'services/preview' }
        else
          @service.save!
          format.html { redirect_to client_trip_days_path(@client, @trip), notice: t('flash.services.update.notice') }
        end
      else
        format.html { render :edit }
        format.js { render :new }
      end
    end
  end

The callback in the Service model :

  def create_or_update_price
    puts "in create or update price"
    if selling_price.present? && price.present?
      self.price.update_columns(:trip_id => trip.id, :currency => trip.client.currency, :purchase_price => purchase_price, :selling_price => selling_price)
    elsif selling_price.present? && !price.present?
      self.price = RegularPrice.create(:trip => trip, :currency => trip.client.currency, :purchase_price => purchase_price, :selling_price => selling_price)
    elsif !selling_price.present? && price.present?
      self.price.destroy
    end
  end

The test :

it "updates the lodging and destroy the price" do
    puts "nombre de service avant création : "
    puts Service.count
    puts "nombre de prix avant création : "
    puts Price.count
    lodging = FactoryGirl.create(:lodging_service, selling_price: 200)
    puts "nombre de service après création : "
    puts Service.count
    puts "nombre de prix après création : "
    puts Price.count
    expect(lodging.reload.price).to be_present
    puts "nombre de prix avant update : "
    puts Price.count
    puts "id"
    puts lodging.id
    patch :update, client_id: client.id, trip_id: trip.id, id: lodging.to_param, service: valid_attributes_no_more_price
    # patch :update, client_id: client.id, trip_id: trip.id, id: lodging.id, service: valid_attributes_with_price
    puts "nombre de prix après update : "
    puts Price.count
    # expect{
    #   patch :update, client_id: client.id, trip_id: trip.id, id: lodging.id, service: valid_attributes_no_more_price
    # }.to change(RegularPrice, :count).by(0)
    expect(lodging.reload.price).to be_nil
  end

  let(:valid_attributes_no_more_price) {
attributes_for(:lodging_service, trip: trip, selling_price: "")

}

As you can see, there is a lot of puts since i try to find what is wrong.

The output is : nombre de service avant création : 0 nombre de prix avant création : 0 in create or update price nombre de service après création : 1 nombre de prix après création : 1 nombre de prix avant update : 1 id 10 nombre de prix après update : 1

Failure/Error: expect(lodging.reload.price).to be_nil

   expected: nil
        got: #<RegularPrice id: 2, label: nil, currency: "CHF", selling_price: 200.0, priceable_type: "Service", p...ated_at: "2017-07-13 08:08:47", quantity: 1, type: "RegularPrice", position: 1, purchase_price: nil>

As we can see, it's look like the callback is not fired after the update, and the action in the controller is not reached.

Have you any idea what is going wrong?

Thanks :)

PS: I always have trouble to include code in my questions, is there a tutorial on how to make it?

回答1:

Since you did not mentioned your ruby version I'll assume it's 2.

First of all you need to learn how to properly debug your code in order to fix the issues yourself.

Here is what you have to do:

1.Add pry gem to your app, pry-byebug there is also a version for ruby 1.9.3.

2.Add a break point in your code

it "updates the lodging and destroy the price" do
  (...) # Code here.

  binding.pry # The debugger  will open a console at this point   

  (...) # Maybe more code here
end

3.Verify all the variable and their values and see where the problem lies

In case you could not find the issue with binding.pry in your rspec file before the expect add it to after the first line of the method, and you can step through the debugger by typing next in the console opened by pry (it will be where your rails server is runnig). If that still does not help, try and add a binding.pry in your classes and see what is the state in there.

Spend a few minutes/hours now to learn debugging and it will save you days/weeks in long term. (while you are learning you don't really know how a program should behave and that extra knowledge is priceless, after a while you only need a debugger for extremely complicated issues).